summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris McDonough <chrism@agendaless.com>2009-05-01 08:02:55 +0000
committerChris McDonough <chrism@agendaless.com>2009-05-01 08:02:55 +0000
commita7a6d7568546dcc88d836653cce8e69916f1e442 (patch)
treecebbe72e3192d49bb4432454fa8cd46228d47cbe
parentc857492756ba39f44a15572341dbdfa076bcb644 (diff)
downloadpyramid-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.txt63
-rw-r--r--docs/narr/models.rst38
-rw-r--r--repoze/bfg/interfaces.py6
-rw-r--r--repoze/bfg/location.py77
-rw-r--r--repoze/bfg/tests/test_location.py58
-rw-r--r--repoze/bfg/tests/test_traversal.py34
-rw-r--r--repoze/bfg/traversal.py54
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"""