Trouble setting LoginManager default user class
I'm trying to port the PTK PersistentUserSource stuff to the new LoginManager. A lot of things seem to be working, but I seem to have fallen into a Catch 22: 1. UserSources.BasicUserSource defines self._defaultClass as LoginUser, where UserSources.LoginUser is a simple RackMountable class (not a ZClass) defined earlier in the file. 2. PTK requires DemoPortal.LoginMember, a ZClass that inherits from LoginUser and PersistentUserSource.MemberMixin (actually, it's having the MemberMixin stuff that's crucial). 3. Rack._v_itemConstructor is a ComputedAttribute that looks at self._defaultClass: if it's a class, it uses it, if it's a string it looks in Products.meta_classes[self._defaultClass] for the class to use. So PersistentUserSource needs to change _defaultClass to refer to DemoPortal.LoginMember. If I try to do it by using a ComputedAttribute: def _defaultClass(self): c = Products.DemoPortal.LoginMember self._defaultClass = c _defaultClass = ComputedAttribute(_defaultClass) I get an error traceback from an AttributeError in Rack.createItem for _v_itemConstructor. BTW: this also happens if I also define _v_itemConstructor as a ComputedAttribute in PersistentUserSource. I need something like ComputedAttributes here, because DemoPortal doesn't (necessarily?) exist at the time PTKDemo is installed. If I try to do it by setting _defaultClass to 'LoginMember', it fails because 'LoginMember' isn't in Products.meta_classes. In fact nothing relating to DemoPortal or any other ZClass product is in Products.meta_classes! The official way to get into that dictionary appears to be to call registerBaseClass or registerZClass. registerZClass would seem like the correct method, but the ONLY call of this is in Products/OFSP/__init__.py for ZClasses.ObjectManager.ZObjectManager. Should ZClass products be registering themselves? If I try to set _defaultClass in PersistentUserSource.__init__. I can't figure out how to refer to /Control_Panel/Products/DemoPortal/LoginMember from there. Looks like I need more Zen. Please enlighten me. Dan Pierson
"Dan L. Pierson" wrote:
I'm trying to port the PTK PersistentUserSource stuff to the new LoginManager. A lot of things seem to be working, but I seem to have fallen into a Catch 22:
1. UserSources.BasicUserSource defines self._defaultClass as LoginUser, where UserSources.LoginUser is a simple RackMountable class (not a ZClass) defined earlier in the file.
2. PTK requires DemoPortal.LoginMember, a ZClass that inherits from LoginUser and PersistentUserSource.MemberMixin (actually, it's having the MemberMixin stuff that's crucial).
3. Rack._v_itemConstructor is a ComputedAttribute that looks at self._defaultClass: if it's a class, it uses it, if it's a string it looks in Products.meta_classes[self._defaultClass] for the class to use.
So PersistentUserSource needs to change _defaultClass to refer to DemoPortal.LoginMember. If I try to do it by using a ComputedAttribute:
def _defaultClass(self): c = Products.DemoPortal.LoginMember self._defaultClass = c
_defaultClass = ComputedAttribute(_defaultClass)
I get an error traceback from an AttributeError in Rack.createItem for _v_itemConstructor. BTW: this also happens if I also define _v_itemConstructor as a ComputedAttribute in PersistentUserSource. I need something like ComputedAttributes here, because DemoPortal doesn't (necessarily?) exist at the time PTKDemo is installed.
The _defaultClass only needs to become DemoPortal.LoginMember before a Portal's LoginManager instance is created. Therefore, you can leave the _defaultClass as LoginUser until the "install" method of DemoPortalBase is called (PTKDemo/Portal.py). In the "install" method, after creating a MembersClass(), set its _defaultClass to LoginMember. ...or have I misunderstood something important? :-) -- Steve Alexander Software Engineer Cat-Box limited
At 10:01 PM 5/17/00 +0100, Steve Alexander wrote:
The _defaultClass only needs to become DemoPortal.LoginMember before a Portal's LoginManager instance is created.
Therefore, you can leave the _defaultClass as LoginUser until the "install" method of DemoPortalBase is called (PTKDemo/Portal.py).
In the "install" method, after creating a MembersClass(), set its _defaultClass to LoginMember.
It would be better to call manage_setStorage(zclass='meta type') rather than tinkering with attributes directly, as manage_setStorage should always be forward-compatible.
..or have I misunderstood something important? :-)
I don't think so. Now if only your message had arrived a bit sooner, I wouldn't have had to write that patch just now... :) On the other hand, it's a useful patch and as a side effect I also now know how to get ComputedAttributes to operate with acquisition (relatively) cheaply. Ah well. :)
In article <14626.61567.192558.386542@sol.control.com>, Dan L. Pierson <dan@sol.control.com> wrote:
If I try to do it by setting _defaultClass to 'LoginMember', it fails because 'LoginMember' isn't in Products.meta_classes. In fact nothing relating to DemoPortal or any other ZClass product is in Products.meta_classes! The official way to get into that dictionary
For a ZClass, the string should look like "Productname/Classname". So try setting _defaultClass to "DemoPortal/LoginMember" instead of just "LoginMember" and see if that works.
Ty Sarna writes:
In article <14626.61567.192558.386542@sol.control.com>, Dan L. Pierson <dan@sol.control.com> wrote:
If I try to do it by setting _defaultClass to 'LoginMember', it fails because 'LoginMember' isn't in Products.meta_classes. In fact nothing relating to DemoPortal or any other ZClass product is in Products.meta_classes! The official way to get into that dictionary
For a ZClass, the string should look like "Productname/Classname". So try setting _defaultClass to "DemoPortal/LoginMember" instead of just "LoginMember" and see if that works.
I think I did... checking... yep, that fails with a KeyError in the Products.meta_classes[c] reference in Rack.py. I expected that because the list of Products.meta_classes keys is: List of keys in Products.meta_class: AccessControl.User/User AccessControl.User/UserFolder OFS.DTMLDocument/DTMLDocument OFS.DTMLMethod/DTMLMethod OFS.Folder/Folder OFS.Image/File OFS.Image/Image Products.BannerClass.BannerClass/BannerManager Products.BannerClass.BannerClass/banner Products.GenericUserFolder.GenericUserFolder/GenericUserFolder Products.GenericUserFolder.User/User Products.LoginManager.UserSources/BasicUserSource Products.LoginManager.UserSources/LoginUser Products.PTKBase.Discussions/Discussable Products.PTKBase.Discussions/DiscussionResponse Products.PTKBase.Document/Document Products.PTKBase.File/File Products.PTKBase.Image/Image Products.PTKBase.Link/Link Products.PTKBase.MemberFolder/MemberBase Products.PTKBase.MemberFolder/MemberFolderBase Products.PTKBase.NewsItem/NewsItem Products.PTKBase.PortalContent/PortalContent Products.PTKBase.PortalFolder/PortalFolder Products.PTKBase.PortalObject/PortalObjectBase Products.PTKDemo.PersistentUserSource/MemberMixin Products.PTKDemo.Portal/DemoPortalBase Products.PTKDemo.SQLMember/DemoSQLMemberBase Products.PTKDemo.SQLMember/DemoSQLMemberFolderBase Products.PTKDemo.ZODBMember/DemoZODBMemberBase Products.PTKDemo.ZODBMember/DemoZODBMemberFolderBase Products.Renderable.Renderable/Renderable Products.ZCatalog.CatalogAwareness/CatalogAware Products.ZCatalog.ZCatalog/ZCatalog Products.ZDBase.ZDiscussions/ZDItem Products.ZDBase.ZDiscussions/ZDTopic Products.ZPatterns.Rack/Rack Products.ZPatterns.Rack/RackMountable Products.ZPatterns.Specialists/Specialist ZClasses.ObjectManager/ObjectManager This is way I claim that ZClass products simply don't get in the list. The site in question has KMnetNews and ZDiscussions installed as well as PTK.
At 03:18 PM 5/17/00 -0400, Dan L. Pierson wrote:
I'm trying to port the PTK PersistentUserSource stuff to the new LoginManager. A lot of things seem to be working, but I seem to have fallen into a Catch 22:
1. UserSources.BasicUserSource defines self._defaultClass as LoginUser, where UserSources.LoginUser is a simple RackMountable class (not a ZClass) defined earlier in the file.
2. PTK requires DemoPortal.LoginMember, a ZClass that inherits from LoginUser and PersistentUserSource.MemberMixin (actually, it's having the MemberMixin stuff that's crucial).
3. Rack._v_itemConstructor is a ComputedAttribute that looks at self._defaultClass: if it's a class, it uses it, if it's a string it looks in Products.meta_classes[self._defaultClass] for the class to use.
It uses: getattr(self, '_zclass', None) or self._defaultClass So as to look for a self._zclass attribute first. _defaultClass is a fallback.
So PersistentUserSource needs to change _defaultClass to refer to DemoPortal.LoginMember. If I try to do it by using a ComputedAttribute:
def _defaultClass(self): c = Products.DemoPortal.LoginMember self._defaultClass = c
_defaultClass = ComputedAttribute(_defaultClass)
Don't use a computed attribute; it won't help you as computed attributes run without acquisition context. This is why _v_defaultItemConstructor wants to have either an actual ZClass reference, or a string that can be looked up in the Python-level registries.
I get an error traceback from an AttributeError in Rack.createItem for _v_itemConstructor. BTW: this also happens if I also define _v_itemConstructor as a ComputedAttribute in PersistentUserSource. I need something like ComputedAttributes here, because DemoPortal doesn't (necessarily?) exist at the time PTKDemo is installed.
Oops. Well, that could be a problem. Here's a question, though. Why does the default class need to be LoginMember? Can't you just set that when you actually create the UserSource?
If I try to do it by setting _defaultClass to 'LoginMember', it fails because 'LoginMember' isn't in Products.meta_classes. In fact nothing relating to DemoPortal or any other ZClass product is in
Products.meta_classes! The official way to get into that dictionary appears to be to call registerBaseClass or registerZClass. registerZClass would seem like the correct method, but the ONLY call of this is in Products/OFSP/__init__.py for ZClasses.ObjectManager.ZObjectManager. Should ZClass products be registering themselves?
This is a limitation of using ComputedAttribute for _v_defaultItemConstructor, which is why manage_setStorage looks up the ZClass in the main ZClass registry, and then sets _zclass to point to it.
If I try to set _defaultClass in PersistentUserSource.__init__. I can't figure out how to refer to /Control_Panel/Products/DemoPortal/LoginMember from there.
You can't do it from __init__, and you don't want to, anyway, because __init__ doesn't have acquisition context. It needs to be in manage_afterAdd and it needs to check whether self._zclass is already set. If not set, then it should call self.manage_setStorage(zclass='meta type you want'). Something like: def manage_afterAdd(self,item,container): UserSource.manage_afterAdd(self,item,container) if not hasattr(self,'_zclass'): self.manage_setStorage(zclass='LoginMember') The above assumes the meta_type is 'LoginMember'; you should change it if appropriate. Sorry for your pain; the _v_itemConstructor is a bit of a hack. I could probably fix this by double-layering ComputedAttributes so that it has acquisition context when it maps from a string to a ZClass. [pause as I hack, implement, test...] Here's a patch that works for me (as in it doesn't break other uses of Rack, I don't know if it'll fix your problem). Try setting _defaultClass to the string representing the meta_type you want, and see if it works. The patch changes things to use a double-layered ComputedAttribute so _v_itemConstructor is called in acquisition context. It also now only sets self._zclass to a meta_type, instead of referencing the ZClass directly. The combination should make it possible to use a string for _defaultClass that refers to a ZClass which is not registered from Python. If it doesn't work, try my other suggestion(s) above, but this is probably the best way to fix it. Index: Rack.py =================================================================== RCS file: /u/idsuser/REPOSITORY/ZProducts/ZPatterns/Rack.py,v retrieving revision 1.45 retrieving revision 1.46 diff -u -r1.45 -r1.46 --- Rack.py 2000/05/05 16:44:24 1.45 +++ Rack.py 2000/05/17 21:20:24 1.46 @@ -185,7 +185,7 @@ if c: if type(c) is type(''): - c = Products.meta_classes[c] + c = self._unifiedZClassRegistry()[c][1] #Products.meta_classes[c] else: def err(key): raise TypeError, "No ZClass set - please use 'Storage' tab" @@ -195,9 +195,8 @@ self._v_itemConstructor = c return c - _v_itemConstructor = ComputedAttribute(_v_itemConstructor) + _v_itemConstructor = ComputedAttribute(lambda s,v=ComputedAttribute(_v_itemConstructor): v) - def _RawItem(self, key): """ Create an empty object of the right class @@ -346,12 +345,12 @@ """ if zclass is not None: if self._unifiedZClassRegistry().has_key(zclass): - if Products.meta_classes.has_key(zclass): + #if Products.meta_classes.has_key(zclass): self._zclass = zclass - else: - self._zclass = self._unifiedZClassRegistry()[zclass][1] - if hasattr(self,'_v_itemConstructor'): - del self._v_itemConstructor + #else: + # self._zclass = self._unifiedZClassRegistry()[zclass][1] + if self.__dict__.has_key('_v_itemConstructor'): + del self._v_itemConstructor else: raise NameError,("Invalid/nonexistent ZClass '%s'" % zclass)
participants (4)
-
Dan L. Pierson -
Phillip J. Eby -
Steve Alexander -
tsarnaļ¼ endicor.com