diff options
| author | Chris McDonough <chrism@agendaless.com> | 2009-05-01 08:02:55 +0000 |
|---|---|---|
| committer | Chris McDonough <chrism@agendaless.com> | 2009-05-01 08:02:55 +0000 |
| commit | a7a6d7568546dcc88d836653cce8e69916f1e442 (patch) | |
| tree | cebbe72e3192d49bb4432454fa8cd46228d47cbe | |
| parent | c857492756ba39f44a15572341dbdfa076bcb644 (diff) | |
| download | pyramid-a7a6d7568546dcc88d836653cce8e69916f1e442.tar.gz pyramid-a7a6d7568546dcc88d836653cce8e69916f1e442.tar.bz2 pyramid-a7a6d7568546dcc88d836653cce8e69916f1e442.zip | |
- The ``repoze.bfg.location.LocationProxy`` class and the
``repoze.bfg.location.ClassAndInstanceDescr`` class have both been
removed in order to be able to eventually shed a dependency on
``zope.proxy``. Neither of these classes was ever an API.
- In all previous releases, the ``repoze.bfg.location.locate``
function worked like so: if a model did not explicitly provide the
``repoze.bfg.interfaces.ILocation`` interface, ``locate`` returned a
``LocationProxy`` object representing ``model`` with its
``__parent__`` attribute assigned to ``parent`` and a ``__name__``
attribute assigned to ``__name__``. In this release, the
``repoze.bfg.location.locate`` function simply jams the ``__name__``
and ``__parent__`` attributes on to the supplied model
unconditionally, no matter if the object implements ILocation or
not, and it never returns a proxy. This was done because the
LocationProxy behavior has now moved into an add-on package
(``repoze.bfg.traversalwrapper``), in order to eventually be able to
shed a dependency on ``zope.proxy``.
- In all previous releases, by default, if traversal was used (as
opposed to URL-dispatch), and the root object supplied
the``repoze.bfg.interfaces.ILocation`` interface, but the children
returned via its ``__getitem__`` returned an object that did not
implement the same interface, :mod:`repoze.bfg` provided some
implicit help during traversal. This traversal feature wrapped
subobjects from the root (and thereafter) that did not implement
``ILocation`` in proxies which automatically provided them with a
``__name__`` and ``__parent__`` attribute based on the name being
traversed and the previous object traversed. This feature has now
been removed from the base ``repoze.bfg`` package for purposes of
eventually shedding a dependency on ``zope.proxy``.
In order to re-enable the wrapper behavior for older applications
which cannot be changed, register the "traversalwrapper"
``ModelGraphTraverser`` as the traversal policy, rather than the
default ``ModelGraphTraverser``. To use this feature, you will need
to install the ``repoze.bfg.traversalwrapper`` package (an add-on
package, available at
http://svn.repoze.org/repoze.bfg.traversalwrapper) Then change your
application's ``configure.zcml`` to include the following stanza:
<adapter
factory="repoze.bfg.traversalwrapper.ModelGraphTraverser"
provides="repoze.bfg.interfaces.ITraverserFactory"
for="*"
/>
When this ITraverserFactory is used instead of the default, no
object in the graph (even the root object) must supply a
``__name__`` or ``__parent__`` attribute. Even if subobjects
returned from the root *do* implement the ILocation interface,
these will still be wrapped in proxies that override the object's
"real" ``__parent__`` and ``__name__`` attributes.
See also changes to the "Models" chapter of the documentation (in
the "Location-Aware Model Instances") section.
| -rw-r--r-- | CHANGES.txt | 63 | ||||
| -rw-r--r-- | docs/narr/models.rst | 38 | ||||
| -rw-r--r-- | repoze/bfg/interfaces.py | 6 | ||||
| -rw-r--r-- | repoze/bfg/location.py | 77 | ||||
| -rw-r--r-- | repoze/bfg/tests/test_location.py | 58 | ||||
| -rw-r--r-- | repoze/bfg/tests/test_traversal.py | 34 | ||||
| -rw-r--r-- | repoze/bfg/traversal.py | 54 |
7 files changed, 80 insertions, 250 deletions
diff --git a/CHANGES.txt b/CHANGES.txt index e8371c661..e51c238b4 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -9,13 +9,17 @@ Index-Related been superseded by a new index location (`http://dist.repoze.org/bfg/current/simple <http://dist.repoze.org/bfg/current/simple>`_). The installation - documentation has been updated. The "lemonade" index still exists, - but it is not guaranteed to have the latest BFG software in it, nor - will it be maintained in the future. + documentation has been updated as well as the ``setup.cfg`` file in + this package. The "lemonade" index still exists, but it is not + guaranteed to have the latest BFG software in it, nor will it be + maintained in the future. Features -------- +- The "paster create" templates have been modified to use links to the + new "bfg.repoze.org" and "docs.repoze.org" websites. + - Added better documentation for virtual hosting at a URL prefix within the virtual hosting docs chapter. @@ -78,6 +82,25 @@ Features Backwards Incompatibilities --------------------------- +- The ``repoze.bfg.location.LocationProxy`` class and the + ``repoze.bfg.location.ClassAndInstanceDescr`` class have both been + removed in order to be able to eventually shed a dependency on + ``zope.proxy``. Neither of these classes was ever an API. + +- In all previous releases, the ``repoze.bfg.location.locate`` + function worked like so: if a model did not explicitly provide the + ``repoze.bfg.interfaces.ILocation`` interface, ``locate`` returned a + ``LocationProxy`` object representing ``model`` with its + ``__parent__`` attribute assigned to ``parent`` and a ``__name__`` + attribute assigned to ``__name__``. In this release, the + ``repoze.bfg.location.locate`` function simply jams the ``__name__`` + and ``__parent__`` attributes on to the supplied model + unconditionally, no matter if the object implements ILocation or + not, and it never returns a proxy. This was done because the + LocationProxy behavior has now moved into an add-on package + (``repoze.bfg.traversalwrapper``), in order to eventually be able to + shed a dependency on ``zope.proxy``. + - In all previous releases, by default, if traversal was used (as opposed to URL-dispatch), and the root object supplied the``repoze.bfg.interfaces.ILocation`` interface, but the children @@ -88,28 +111,30 @@ Backwards Incompatibilities ``ILocation`` in proxies which automatically provided them with a ``__name__`` and ``__parent__`` attribute based on the name being traversed and the previous object traversed. This feature has now - been disabled in the default configuration for purposes of speed and - understandability. - - In order to re-enable the ILocation wrapper behavior for older - applications which cannot be changed, register the - ``WrappingModelGraphTraverser`` as the traversal policy, rather than - the default ``ModelGraphTraverser``. To use this feature, your - application will need to have the following in its - ``configure.zcml``:: + been removed from the base ``repoze.bfg`` package for purposes of + eventually shedding a dependency on ``zope.proxy``. + + In order to re-enable the wrapper behavior for older applications + which cannot be changed, register the "traversalwrapper" + ``ModelGraphTraverser`` as the traversal policy, rather than the + default ``ModelGraphTraverser``. To use this feature, you will need + to install the ``repoze.bfg.traversalwrapper`` package (an add-on + package, available at + http://svn.repoze.org/repoze.bfg.traversalwrapper) Then change your + application's ``configure.zcml`` to include the following stanza: <adapter - factory="repoze.bfg.traversal.WrappingModelGraphTraverser" + factory="repoze.bfg.traversalwrapper.ModelGraphTraverser" provides="repoze.bfg.interfaces.ITraverserFactory" for="*" /> - When this ITraverserFactory is used, no object in the graph (even - the root object) must supply a ``__name__`` or ``__parent__`` - attribute. Even if subobjects returned from the root *do* - implement the ILocation interface, these will still be wrapped in - proxies that override the object's "real" ``__parent__`` and - ``__name__`` attributes. + When this ITraverserFactory is used instead of the default, no + object in the graph (even the root object) must supply a + ``__name__`` or ``__parent__`` attribute. Even if subobjects + returned from the root *do* implement the ILocation interface, + these will still be wrapped in proxies that override the object's + "real" ``__parent__`` and ``__name__`` attributes. See also changes to the "Models" chapter of the documentation (in the "Location-Aware Model Instances") section. diff --git a/docs/narr/models.rst b/docs/narr/models.rst index 624a29002..61e313830 100644 --- a/docs/narr/models.rst +++ b/docs/narr/models.rst @@ -124,31 +124,37 @@ and so on. .. note:: If you'd rather not manage the ``__name__`` and ``__parent__`` - attributes of your models "by hand", :mod:`repoze.bfg`` can help you - do this. - - In order to use this helper feature, you must first register the - ``WrappingModelGraphTraverser`` as the traversal policy, rather than - the default ``ModelGraphTraverser``. To register the - ``WrappingModelGraphTraverser`` as the traversal policy, your - application will need to have the following in its - ``configure.zcml`` file: + attributes of your models "by hand", an add-on package to + :mod:`repoze.bfg`` named :mod:`repoze.bfg.traversalwrapper` can help + you do this. + + In order to use this helper feature, you must first install the + :mod:`repoze.bfg.traversalwrapper` package (available from + `http://svn.repoze.org/repoze.bfg.traversalwrapper + <http://svn.repoze.org/repoze.bfg.traversalwrapper>`_), then + register its ``ModelGraphTraverser`` as the traversal policy, rather + than the default BFG ``ModelGraphTraverser``. To register the + :mod:`repoze.bfg.traversalwrapper` ``ModelGraphTraverser`` as the + traversal policy, your application will need to have the following + in its ``configure.zcml`` file: .. code-block:: xml <adapter - factory="repoze.bfg.traversal.WrappingModelGraphTraverser" + factory="repoze.bfg.traversalwrapper.ModelGraphTraverser" provides="repoze.bfg.interfaces.ITraverserFactory" for="*" /> - If this statement is made in ZCML, you don't need to manage the - ``__parent__`` and ``__name__`` attributes on graph objects "by + If this statement is made in ZCML, you will no longer need to manage + the ``__parent__`` and ``__name__`` attributes on graph objects "by hand". Instead, as necessary, during traversal :mod:`repoze.bfg` - will wrap each object in a ``LocationProxy`` which will dynamically - assign a ``__name__`` and a ``__parent__`` to the traversed object - (based on the last traversed object and the name supplied to - ``__getitem__``). + will wrap each object (even the root object) in a ``LocationProxy`` + which will dynamically assign a ``__name__`` and a ``__parent__`` to + the traversed object (based on the last traversed object and the + name supplied to ``__getitem__``). The root object will have a + ``__name__`` attribute of ``None`` and a ``__parent__`` attribute + of ``None``. :mod:`repoze.bfg` API Functions That Act Against Models ------------------------------------------------------- diff --git a/repoze/bfg/interfaces.py b/repoze/bfg/interfaces.py index cb0220a2e..537bb4455 100644 --- a/repoze/bfg/interfaces.py +++ b/repoze/bfg/interfaces.py @@ -179,6 +179,8 @@ class IWSGIApplicationCreatedEvent(IObjectEvent): app = Attribute(u"Published application") +# this interface, even if it becomes unused within BFG, is imported by +# other packages (such as repoze.bfg.traversalwrapper) class ILocation(Interface): """Objects that have a structural location""" @@ -223,4 +225,6 @@ class IContextURL(Interface): def __call__(): """ Return a URL that points to the context """ -VH_ROOT_KEY = 'HTTP_X_VHM_ROOT' +# VH_ROOT_KEY is an interface; its imported from other packages (e.g. +# traversalwrapper) +VH_ROOT_KEY = 'HTTP_X_VHM_ROOT' diff --git a/repoze/bfg/location.py b/repoze/bfg/location.py index ed7d2ad1f..7e9d622c2 100644 --- a/repoze/bfg/location.py +++ b/repoze/bfg/location.py @@ -12,15 +12,11 @@ # ############################################################################## -"""Location support borrowed from ``zope.location``, but without -``zope.security`` support, which is not used by ``repoze.bfg`` +"""Location support loosely based from ``zope.location``, but without +``zope.security`` support or proxy support, neither of which is used +by ``repoze.bfg`` """ -import zope.interface -from repoze.bfg.interfaces import ILocation -from zope.proxy import ProxyBase, getProxiedObject, non_overridable -from zope.proxy.decorator import DecoratorSpecificationDescriptor - def inside(model1, model2): """Is ``model1`` 'inside' ``model2``? Return ``True`` if so, else ``False``. @@ -38,25 +34,13 @@ def inside(model1, model2): def locate(model, parent, name=None): """ - If ``model`` explicitly provides the - ``repoze.bfg.interfaces.ILocation`` interface, directly set - ``model`` 's ``__parent__`` attribute to the ``parent`` object - (also a model), and its ``__name__`` to the supplied ``name`` - argument, and return the model. - - If ``model`` does *not* explicitly provide the - ``repoze.bfg.interfaces.ILocation`` interface, return a - ``LocationProxy`` object representing ``model`` with its - ``__parent__`` attribute assigned to ``parent`` and a ``__name__`` - attribute assigned to ``__name__``. A ``LocationProxy`` object is - an unpickleable proxy that can 'stand in' for arbitrary object - instances. + Directly set ``model`` 's ``__parent__`` attribute to the + ``parent`` object (also a model), and its ``__name__`` to the + supplied ``name`` argument, and return the model. """ - if ILocation.providedBy(model): - model.__parent__ = parent - model.__name__ = name - return model - return LocationProxy(model, parent, name) + model.__parent__ = parent + model.__name__ = name + return model def lineage(model): """ @@ -83,46 +67,3 @@ def lineage(model): yield model model = getattr(model, '__parent__', None) -class ClassAndInstanceDescr(object): - - def __init__(self, *args): - self.funcs = args - - def __get__(self, inst, cls): - if inst is None: - return self.funcs[1](cls) - return self.funcs[0](inst) - -class LocationProxy(ProxyBase): - """Location-object proxy - - This is a non-picklable proxy that can be put around objects that - don't implement `ILocation`. - """ - - zope.interface.implements(ILocation) - - __slots__ = '__parent__', '__name__' - __safe_for_unpickling__ = True - - def __new__(self, ob, container=None, name=None): - return ProxyBase.__new__(self, ob) - - def __init__(self, ob, container=None, name=None): - ProxyBase.__init__(self, ob) - self.__parent__ = container - self.__name__ = name - - @non_overridable - def __reduce__(self, proto=None): - raise TypeError("Not picklable") - - __doc__ = ClassAndInstanceDescr( - lambda inst: getProxiedObject(inst).__doc__, - lambda cls, __doc__ = __doc__: __doc__, - ) - - __reduce_ex__ = __reduce__ - - __providedBy__ = DecoratorSpecificationDescriptor() - diff --git a/repoze/bfg/tests/test_location.py b/repoze/bfg/tests/test_location.py index f297a9d6c..9de059a86 100644 --- a/repoze/bfg/tests/test_location.py +++ b/repoze/bfg/tests/test_location.py @@ -17,8 +17,6 @@ class TestLocation(unittest.TestCase): def test_locate(self): from repoze.bfg.location import locate - from repoze.bfg.location import LocationProxy - a = Location() parent = Location() a_located = locate(a, parent, 'a') @@ -30,40 +28,6 @@ class TestLocation(unittest.TestCase): a_located_2 = locate(a_located, parent, 'a') self.failUnless(a_located_2 is a_located) - # If the object does not provide ILocation a LocationProxy is returned: - - l = [1, 2, 3] - parent = Location() - l_located = locate(l, parent, 'l') - self.assertEqual(l_located, [1, 2, 3]) - self.failUnless(l_located.__parent__ is parent) - self.assertEqual(l_located.__name__, 'l') - self.failIf(l_located is l) - self.assertEqual(type(l_located), LocationProxy) - - l_located_2 = locate(l_located, parent, 'l') - self.failUnless(l_located_2 is l_located) - # When changing the name, we still do not get a different proxied - # object: - - l_located_3 = locate(l_located, parent, 'new-name') - self.failUnless(l_located_3 is l_located_2) - - def test_LocationProxy(self): - from repoze.bfg.location import LocationProxy - from repoze.bfg.interfaces import ILocation - l = [1, 2, 3] - self.assertEqual(ILocation.providedBy(l), False) - p = LocationProxy(l, "Dad", "p") - self.assertEqual(p, [1, 2, 3]) - self.assertEqual(ILocation.providedBy(p), True) - self.assertEqual(p.__parent__, 'Dad') - self.assertEqual(p.__name__, 'p') - import pickle - self.assertRaises(TypeError, pickle.dumps, p) - # Proxies should get their doc strings from the object they proxy: - self.assertEqual(p.__doc__, l.__doc__) - def test_lineage(self): from repoze.bfg.location import lineage o1 = Location() @@ -75,28 +39,6 @@ class TestLocation(unittest.TestCase): result = list(lineage(o1)) self.assertEqual(result, [o1]) -class TestClassAndInstanceDescr(unittest.TestCase): - def _getTargetClass(self): - from repoze.bfg.location import ClassAndInstanceDescr - return ClassAndInstanceDescr - - def _makeOne(self, *arg): - return self._getTargetClass()(*arg) - - def test__get__noinst(self): - def f(ob): - return ob - ob = self._makeOne(f, f) - result = ob.__get__(None, 1) - self.assertEqual(result, 1) - - def test__get__withinst(self): - def f(ob): - return ob - ob = self._makeOne(f, f) - result = ob.__get__(1, 2) - self.assertEqual(result, 1) - from repoze.bfg.interfaces import ILocation from zope.interface import implements class Location(object): diff --git a/repoze/bfg/tests/test_traversal.py b/repoze/bfg/tests/test_traversal.py index 942f84684..f361d0a79 100644 --- a/repoze/bfg/tests/test_traversal.py +++ b/repoze/bfg/tests/test_traversal.py @@ -189,40 +189,6 @@ class ModelGraphTraverserTests(unittest.TestCase): environ = self._getEnviron(PATH_INFO='/%s' % segment) self.assertRaises(TypeError, policy, environ) -class WrappingModelGraphTraverserTests(ModelGraphTraverserTests): - - def _getTargetClass(self): - from repoze.bfg.traversal import WrappingModelGraphTraverser - return WrappingModelGraphTraverser - - def test_call_proxies(self): - baz = DummyContext() - bar = DummyContext(baz) - foo = DummyContext(bar) - root = DummyContext(foo) - from zope.proxy import isProxy - policy = self._makeOne(root) - environ = self._getEnviron(PATH_INFO='/foo/bar/baz') - ctx, name, subpath, traversed, vroot, vroot_path = policy(environ) - self.assertEqual(name, '') - self.assertEqual(subpath, []) - self.assertEqual(ctx, baz) - self.failUnless(isProxy(ctx)) - self.assertEqual(ctx.__name__, 'baz') - self.assertEqual(ctx.__parent__, bar) - self.failUnless(isProxy(ctx.__parent__)) - self.assertEqual(ctx.__parent__.__name__, 'bar') - self.assertEqual(ctx.__parent__.__parent__, foo) - self.failUnless(isProxy(ctx.__parent__.__parent__)) - self.assertEqual(ctx.__parent__.__parent__.__name__, 'foo') - self.assertEqual(ctx.__parent__.__parent__.__parent__, root) - self.failUnless(isProxy(ctx.__parent__.__parent__.__parent__)) - self.assertEqual(ctx.__parent__.__parent__.__parent__.__name__, None) - self.assertEqual(ctx.__parent__.__parent__.__parent__.__parent__, None) - self.assertEqual(traversed, [u'foo', u'bar', u'baz']) - self.assertEqual(vroot, root) - self.assertEqual(vroot_path, []) - class FindInterfaceTests(unittest.TestCase): def _callFUT(self, context, iface): from repoze.bfg.traversal import find_interface diff --git a/repoze/bfg/traversal.py b/repoze/bfg/traversal.py index 901368bba..f4f64484f 100644 --- a/repoze/bfg/traversal.py +++ b/repoze/bfg/traversal.py @@ -9,7 +9,6 @@ from zope.deferredimport import deprecated from zope.interface import classProvides from zope.interface import implements -from repoze.bfg.location import LocationProxy from repoze.bfg.location import lineage from repoze.bfg.lru import lru_cache @@ -421,59 +420,6 @@ class ModelGraphTraverser(object): return ob, '', [], traversed, vroot, vroot_path -class WrappingModelGraphTraverser(ModelGraphTraverser): - """ A model graph traverser that should be used (for convenience) - when no object in the graph supplies either a ``__name__`` or a - ``__parent__`` attribute (ie. no object 'provides ILocation') .""" - classProvides(ITraverserFactory) - implements(ITraverser) - def __init__(self, root): - self.root = root - - def __call__(self, environ, _marker=_marker): - try: - path = environ['PATH_INFO'] - except KeyError: - path = '/' - try: - vroot_path_string = environ[VH_ROOT_KEY] - except KeyError: - vroot_path = [] - vroot_idx = 0 - else: - vroot_path = list(traversal_path(vroot_path_string)) - vroot_idx = len(vroot_path) - path = vroot_path_string + path - - path = list(traversal_path(path)) - - traversed = [] - - ob = vroot = LocationProxy(self.root) - name = '' - - i = 1 - - for segment in path: - if segment[:2] =='@@': - return ob, segment[2:], path[i:], traversed, vroot, vroot_path - try: - getitem = ob.__getitem__ - except AttributeError: - return ob, segment, path[i:], traversed, vroot, vroot_path - try: - next = getitem(segment) - except KeyError: - return ob, segment, path[i:], traversed, vroot, vroot_path - next = LocationProxy(next, ob, segment) - if vroot_idx == i-1: - vroot = ob - traversed.append(segment) - ob = next - i += 1 - - return ob, '', [], traversed, vroot, vroot_path - class TraversalContextURL(object): """ The IContextURL adapter used to generate URLs for a context object obtained via graph traversal""" |
