Index: CHANGES.txt =================================================================== --- CHANGES.txt (revision 90362) +++ CHANGES.txt (working copy) @@ -4,6 +4,14 @@ ================== +3.4.1 (unreleased) +================== + +- Annotation factories take care not to store proxies in the database, so + adapting an object wrapped in a LocationProxy works correctly. + + +================== 3.4.0 (2007-08-29) ================== Index: setup.py =================================================================== --- setup.py (revision 90362) +++ setup.py (working copy) @@ -60,6 +60,7 @@ 'zope.interface', 'zope.component', 'zope.location>=3.4.0b1.dev-r78903', + 'zope.proxy', ], extras_require = dict( test = ['zope.testing', Index: src/zope/annotation/README.txt =================================================================== --- src/zope/annotation/README.txt (revision 90362) +++ src/zope/annotation/README.txt (working copy) @@ -124,3 +124,46 @@ 'my.unique.key' >>> zope.location.interfaces.ILocation.providedBy(old_hoi) True + + +LocationProxies +--------------- + +Suppose your annotation proxy provides ILocation. + + >>> class IPoloi(interface.Interface): + ... pass + >>> class Poloi(Persistent): + ... interface.implements(IPoloi, zope.location.interfaces.ILocation) + ... component.adapts(IFoo) + ... __name__ = __parent__ = 0 + >>> component.provideAdapter(factory(Poloi, 'my.other.key')) + +Sometimes you're adapting an object wrapped in a LocationProxy. + + >>> foo4 = Foo() + >>> import zope.location.location + >>> wrapped_foo4 = zope.location.location.LocationProxy(foo4, None, 'foo4') + >>> located_poloi = IPoloi(wrapped_foo4) + +At first glance it looks as if located_poloi is located under wrapped_foo4. + + >>> located_poloi.__parent__ is wrapped_foo4 + True + >>> located_poloi.__name__ + 'my.other.key' + +but that's because we received a LocationProxy + + >>> print type(located_poloi).__name__ + LocationProxy + +If we unwrap located_poloi and look at it directly, we'll see it stores a +reference to the real Foo object + + >>> from zope.proxy import removeAllProxies + >>> removeAllProxies(located_poloi).__parent__ is foo4 + True + >>> removeAllProxies(located_poloi).__name__ + 'my.other.key' + Index: src/zope/annotation/factory.py =================================================================== --- src/zope/annotation/factory.py (revision 90362) +++ src/zope/annotation/factory.py (working copy) @@ -18,6 +18,8 @@ import zope.component import zope.interface import zope.location.location +import zope.location.interfaces +import zope.proxy import zope.annotation.interfaces @@ -43,11 +45,14 @@ except KeyError: result = factory() annotations[key] = result - # Location has to be set up late to allow location proxies - # to be applied, if needed. This does not trigger an event and is idempotent - # if location or containment is set up already. - located_result = zope.location.location.located(result, context, key) - return located_result + if zope.location.interfaces.ILocation.providedBy(result): + zope.location.location.locate(result, + zope.proxy.removeAllProxies(context), key) + if not (zope.location.interfaces.ILocation.providedBy(result) + and result.__parent__ is context + and result.__name__ == key): + result = zope.location.location.LocationProxy(result, context, key) + return result # Convention to make adapter introspectable, used by apidoc getAnnotation.factory = factory