[Zope-dev] Interfaces vs ZCA concepts
Tres Seaver
tseaver at palladion.com
Wed Dec 16 16:39:13 EST 2009
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
Martin Aspeli wrote:
> Tres Seaver wrote:
>> Martin Aspeli wrote:
>>> zope.component raises TypeError if you can't adapt. It raises
>>> ComponentLookupError it can't find a utility.
>> Not so: see $ZSVN/zope.component/trunk/src/zope/component/registry.py:
>
> I'm pretty sure you get a TypeError when Zope can't adapt. I'm not sure
> where it's thrown from, though.
>
> Stupid example:
>
> >>> from plone.portlets.interfaces import IPortletType
> >>> class X(object): pass
> ...
> >>> x = ()
> >>> IPortletType(x)
> Traceback (most recent call last):
> File "<console>", line 1, in <module>
> TypeError: ('Could not adapt', (), <InterfaceClass
> plone.portlets.interfaces.IPortletType>)
The "Could not adapt" traceback tells you that it isnt The ZCA doing
that: it is the C code inside zope.interface. One might argue that a
better exception would be LookupError: we haven't "violted the
contract" here.
>> class Components:
>> ...
>> def getUtility(self, provided, name=u''):
>> utility = self.utilities.lookup((), provided, name)
>> if utility is None:
>> raise ComponentLookupError(provided, name)
>> return utility
>> ...
>> def getAdapter(self, object, interface, name=u''):
>> adapter = self.adapters.queryAdapter(object, interface, name)
>> if adapter is None:
>> raise ComponentLookupError(object, interface, name)
>> return adapter
>
> getAdapter() is different, though:
>
> >>> from zope.component import getAdapter
> >>> getAdapter(x, IPortletType)
> Traceback (most recent call last):
> File "<console>", line 1, in <module>
> File
> "/Users/optilude/.buildout/eggs/zope.component-3.7.1-py2.6.egg/zope/component/_api.py",
> line 98, in getAdapter
> raise ComponentLookupError(object, interface, name)
> ComponentLookupError: ((), <InterfaceClass
> plone.portlets.interfaces.IPortletType>, u'')
>
>> which matches the contract spelled out in the docstrings for IComponent.
>> That class raises TypeError only for invalid values passed to the
>> various registration functions.
>
> Something else is raising TypeError then. :)
The interface machinery catches whatever the adapter hook raises and
returns a TypeError instead.
>> At any rate, we are talking about errors raised from zope.itnerface
>> APIs, which nowhere mention or use CLE::
>
> Ok.
>
>> $ svn info . | grep URL
>> URL: svn+ssh://svn.zope.org/repos/main/zope.interface/trunk
>> $ svn up
>> At revision 106615.
>> $ find . -name "*.py" | xargs grep ComponentLookupError
>> $
>>
>> Nobody calling an interface today has any *defined* behavior to expect
>> in the case of failure (in fact, '__call__' is not even part of IInterface!)
>>
>> Please point to existing code which calls 'IFoo.utility(name="bar")' and
>> catches a CLE. Since this is a new API we are talkign about, there
>> can't be any BBB concerns.
>
> True, but we're also going to ask people to change their use of
> getUtility(IFoo) to IFoo.utility and ditto for adaption. If I have
> existing code that looks like this:
>
> try:
> foo = IFoo(bar)
> except TypeError:
> pass
>
> I would like to be able to move that "mechanically" to:
>
> try:
> foo = IFoo.adapt(bar)
> except TypeError:
> pass
I can't see anything compelling about making that transform mechanical.
As noted above, it is already *wrong* to be relying on a specific
exception type here anyway.
> If I have to change the exception type in any of the scenarios (utility
> lookup would be similar) then that would be another change to detect,
> and possibly a harder one to spot in less contrived code.
>
>> Any code today which wants a utility is calling 'getUtilty' (if it
>> *knows* the utility must be registered) or 'queryUtility' (if it thinks
>> it might not be). Less facetiously than my first challenge: please
>> point to actual code in the wild which looks like::
>>
>> try:
>> foo = getUtilty(IFoo, name='bar')
>> except ComponentLookupError:
>> # do something
>>
>> instead of::
>>
>> foo = queryUtility(IFoo, name='bar')
>> if foo is None:
>> # do something
>>
>> I will argue that any code doing the first, outside of maybe tests of
>> the ZCA itself is plain broken.
>
> Perhaps, but I'm pretty sure people have done this. They may also have
> done it in tests.
Why would we bend over backward to keep obviously broken code seeming to
work?
> I'm not religious about it, but I think that if we're only changing the
> API, it'd be preferable not to change the exceptions we throw unless
> semantics also change.
Given that the behavior isn't part of any API to date, I'm suggesting
that we *document* the behavior ahead of time (for new code), without
any regard for BBB. We could document the existing __call__ behavior as
well, if needed.
In either case, I think TypeError (or maybe LookupError) is the *right*
choice: we don't want to "hide" zope.component's API functions and then
turn around and require folks to import zope.component just to catch its
local exception types.
Tres.
- --
===================================================================
Tres Seaver +1 540-429-0999 tseaver at palladion.com
Palladion Software "Excellence by Design" http://palladion.com
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.9 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org
iEYEARECAAYFAkspU4EACgkQ+gerLs4ltQ7koQCgpoHUw8vQZfAQcJec9zWAdKhU
V3kAoIliRpCfujwFSCIs4Gi6z+BIwq0N
=2FUT
-----END PGP SIGNATURE-----
More information about the Zope-Dev
mailing list