zope3, browser:addMenuItem, ZCML factory => ForbiddenAttribute: ('__call__', <...>)
Hi, I had some difficulty to use "browser:addMenuItem" ZCML directive : <browser:addMenuItem factory="myproject.MyContent" title="MyContent" permission="zope.ManageContent" /> with my Factory : <utility factory=".mycontent.MyContentFactory" name="myproject.MyContent" permission="zope.Public" /> mycontent.py file : from zope.component.interfaces import IFactory ... class MyContentFactory(object): implements(IFactory) title = u"Create a new MyContent" description = u"This factory instantiates new MyContent" def __call__(self): return MyContent() def getInterfaces(self): return implementedBy(MyContent) Now, if I try to append a MyContent object through ZMI I've this error : File "/home/harobed/buildout-eggs/zope.app.container-3.6.0-py2.4-linux- i686.egg/zope/app/container/browser/adding.py", line 145, in action content = factory() File "/home/harobed/buildout-eggs/zope.security-3.5.2-py2.4-linux- i686.egg/zope/security/checker.py", line 463, in check self._checker2.check(object, name) ForbiddenAttribute: ('__call__', <myproject.mycontent.MyContentFactory object at 0x93f5b0c>) Well, if I look in zope/app/container/browser/adding.py, in Adding.action method I see this comment : # TODO: If the factory wrapped by LocationProxy is already a Proxy, # then ProxyFactory does not do the right thing and the # original's checker info gets lost. No factory that was # registered via ZCML and was used via addMenuItem worked # here. (SR) I think "No factory that was registered via ZCML and was used via addMenuItem worked here" speak about my issue ? I've looked in zope.app.container browser test and I found this tip : mycontent.py file fixed with the tip : from zope.component.interfaces import IFactory import zope.security.checker ... class MyContentFactory(object): implements(IFactory) title = u"Create a new MyContent" description = u"This factory instantiates new MyContent" def __init__(self): self.__Security_checker__ = zope.security.checker.NamesChecker (['__call__']) def __call__(self): return MyContent() def getInterfaces(self): return implementedBy(MyContent) With this __Security_checker__ property my issue is fixed, now I can add a MyContent object through ZMI. Now, I've some comment and question about it : * I think this tip isn't "developer friendly", what is the good method ? * Philipp von Weitershausen's book (Web Component Development with Zope 3) give first version of my example (without __Security_checker__ tip) and its example didn't working with zope 3.4 (zopeproject use). Why this compatibility breaking ? Regards, Stephane
Le Fri, 19 Sep 2008 23:30:21 +0000, KLEIN Stéphane a écrit :
Now, I've some comment and question about it :
* I think this tip isn't "developer friendly", what is the good method ?
* Philipp von Weitershausen's book (Web Component Development with Zope 3) give first version of my example (without __Security_checker__ tip) and its example didn't working with zope 3.4 (zopeproject use). Why this compatibility breaking ?
Well, I've this problem with zope.component 3.5.1, it's unstable version. It's a answer to "Why this compatibility breaking". I think it's a bug. I know what revision bring the issue : http://svn.zope.org/zope.component/ trunk/src/zope/component/zcml.py?rev=88794&view=rev Before the utility function in zope/component/zcml.py is : def utility(_context, provides=None, component=None, factory=None, permission=None, name=''): if factory: if component: raise TypeError("Can't specify factory and component.") component = factory() if provides is None: if factory: provides = list(zope.interface.implementedBy(factory)) else: provides = list(zope.interface.providedBy(component)) if len(provides) == 1: provides = provides[0] else: raise TypeError("Missing 'provides' attribute") if permission is not None: if permission == PublicPermission: permission = CheckerPublic checker = InterfaceChecker(provides, permission) component = proxify(component, checker) _context.action( discriminator = ('utility', provides, name), callable = handler, args = ('registerUtility', component, provides, name) ) _context.action( discriminator = None, callable = provideInterface, args = (provides.__module__ + '.' + provides.getName(), provides) ) now it's : def utility(_context, provides=None, component=None, factory=None, permission=None, name=''): if factory and component: raise TypeError("Can't specify factory and component.") if provides is None: if factory: provides = list(zope.interface.implementedBy(factory)) else: provides = list(zope.interface.providedBy(component)) if len(provides) == 1: provides = provides[0] else: raise TypeError("Missing 'provides' attribute") if permission is not None: if permission == PublicPermission: permission = CheckerPublic checker = InterfaceChecker(provides, permission) component = proxify(component, checker) _context.action( discriminator = ('utility', provides, name), callable = handler, args = ('registerUtility', component, provides, name), kw = dict(factory=factory), ) _context.action( discriminator = None, callable = provideInterface, args = (provides.__module__ + '.' + provides.getName(), provides) ) So, in new version, if factory is given then permission isn't used because component is None. Before, component was builded with factory and permission was applied on this component and this ZCML declaration worked perfeclty with "browser:addMenuItem". Now, I don't know how can I fix this issue with new Utility ZMCL design. I've reported this bug here : https://bugs.launchpad.net/zope3/+bug/272595 Regards, Stephane
participants (1)
-
KLEIN Stéphane