diff options
| author | Chris McDonough <chrism@agendaless.com> | 2008-09-28 02:17:36 +0000 |
|---|---|---|
| committer | Chris McDonough <chrism@agendaless.com> | 2008-09-28 02:17:36 +0000 |
| commit | cbdc36976c18a0812f921ee3b7b92ed2dd823ed0 (patch) | |
| tree | c428c9b0e4357ecf3b5903359594dc6f2bf27a8b | |
| parent | cd6899ed4d0eba4b114d04058470528c9a167d6e (diff) | |
| download | pyramid-cbdc36976c18a0812f921ee3b7b92ed2dd823ed0.tar.gz pyramid-cbdc36976c18a0812f921ee3b7b92ed2dd823ed0.tar.bz2 pyramid-cbdc36976c18a0812f921ee3b7b92ed2dd823ed0.zip | |
Features
- A ``repoze.bfg.location`` API module was added.
Backwards incompatibilities
- Applications must now use the ``repoze.bfg.interfaces.ILocation``
interface rather than ``zope.location.interfaces.ILocation`` to
represent that a model object is "location-aware". We've removed
a dependency on ``zope.location`` for cleanliness purposes: as
new versions of zope libraries are released which have improved
dependency information, getting rid of our dependence on
``zope.location`` will prevent a newly installed repoze.bfg
application from requiring the ``zope.security``, egg, which not
truly used at all in a "stock" repoze.bfg setup. These
dependencies are still required by the stack at this time; this
is purely a futureproofing move.
The security and model documentation for previous versions of
``repoze.bfg`` recommended using the
``zope.location.interfaces.ILocation`` interface to represent
that a model object is "location-aware". This documentation has
been changed to reflect that this interface should now be
imported from ``repoze.bfg.interfaces.ILocation`` instead.
| -rw-r--r-- | CHANGES.txt | 27 | ||||
| -rw-r--r-- | LICENSE.txt | 60 | ||||
| -rw-r--r-- | docs/api/location.rst | 14 | ||||
| -rw-r--r-- | docs/index.rst | 1 | ||||
| -rw-r--r-- | docs/narr/models.rst | 21 | ||||
| -rw-r--r-- | docs/narr/security.rst | 48 | ||||
| -rw-r--r-- | repoze/bfg/interfaces.py | 8 | ||||
| -rw-r--r-- | repoze/bfg/location.py | 132 | ||||
| -rw-r--r-- | repoze/bfg/security.py | 6 | ||||
| -rw-r--r-- | repoze/bfg/tests/test_location.py | 82 | ||||
| -rw-r--r-- | repoze/bfg/tests/test_traversal.py | 2 | ||||
| -rw-r--r-- | repoze/bfg/tests/test_zcml.py | 6 | ||||
| -rw-r--r-- | repoze/bfg/traversal.py | 16 | ||||
| -rw-r--r-- | repoze/bfg/zcml.py | 8 | ||||
| -rw-r--r-- | setup.py | 16 |
15 files changed, 402 insertions, 45 deletions
diff --git a/CHANGES.txt b/CHANGES.txt index 82156c484..71537b48e 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,3 +1,30 @@ +Next release + + Features + + - A ``repoze.bfg.location`` API module was added. + + Backwards incompatibilities + + - Applications must now use the ``repoze.bfg.interfaces.ILocation`` + interface rather than ``zope.location.interfaces.ILocation`` to + represent that a model object is "location-aware". We've removed + a dependency on ``zope.location`` for cleanliness purposes: as + new versions of zope libraries are released which have improved + dependency information, getting rid of our dependence on + ``zope.location`` will prevent a newly installed repoze.bfg + application from requiring the ``zope.security``, egg, which not + truly used at all in a "stock" repoze.bfg setup. These + dependencies are still required by the stack at this time; this + is purely a futureproofing move. + + The security and model documentation for previous versions of + ``repoze.bfg`` recommended using the + ``zope.location.interfaces.ILocation`` interface to represent + that a model object is "location-aware". This documentation has + been changed to reflect that this interface should now be + imported from ``repoze.bfg.interfaces.ILocation`` instead. + 0.3.8 (08/26/2008) Docs diff --git a/LICENSE.txt b/LICENSE.txt index 5ced96e3b..af4b8ecc6 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -1,4 +1,4 @@ -License +The majority of the code in bfg is supplied under this license: A copyright notice accompanies this license document that identifies the copyright holders. @@ -39,3 +39,61 @@ License THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +Portions of the code in repoze.bfg are supplied under the ZPL (headers +within individiual files indicate that these portions are licensed +under the ZPL): + +Zope Public License (ZPL) Version 2.1 +------------------------------------- + +A copyright notice accompanies this license document that +identifies the copyright holders. + +This license has been certified as open source. It has also +been designated as GPL compatible by the Free Software +Foundation (FSF). + +Redistribution and use in source and binary forms, with or +without modification, are permitted provided that the +following conditions are met: + +1. Redistributions in source code must retain the + accompanying copyright notice, this list of conditions, + and the following disclaimer. + +2. Redistributions in binary form must reproduce the accompanying + copyright notice, this list of conditions, and the + following disclaimer in the documentation and/or other + materials provided with the distribution. + +3. Names of the copyright holders must not be used to + endorse or promote products derived from this software + without prior written permission from the copyright + holders. + +4. The right to distribute this software or to use it for + any purpose does not give you the right to use + Servicemarks (sm) or Trademarks (tm) of the copyright + holders. Use of them is covered by separate agreement + with the copyright holders. + +5. If any files are modified, you must cause the modified + files to carry prominent notices stating that you changed + the files and the date of any change. + +Disclaimer + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' + AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT + NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + NO EVENT SHALL THE COPYRIGHT HOLDERS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + DAMAGE. diff --git a/docs/api/location.rst b/docs/api/location.rst new file mode 100644 index 000000000..dc7d50a2f --- /dev/null +++ b/docs/api/location.rst @@ -0,0 +1,14 @@ +.. _location_module: + +:mod:`repoze.bfg.location` +-------------------------- + +.. automodule:: repoze.bfg.location + + .. autofunction:: lineage + + .. autofunction:: inside + + .. autofunction:: locate + + diff --git a/docs/index.rst b/docs/index.rst index 8c0660246..594add0cb 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -72,6 +72,7 @@ Per-module :mod:`repoze.bfg` API documentation. api/security api/template api/traversal + api/location api/urldispatch api/view api/wsgi diff --git a/docs/narr/models.rst b/docs/narr/models.rst index 7df265657..e627a682c 100644 --- a/docs/narr/models.rst +++ b/docs/narr/models.rst @@ -74,7 +74,7 @@ by via ``__getitem__``. If you choose not to manage the ``__name__`` and ``__parent__`` attributes of your models "by hand", :mod:`repoze.bfg`` is willing to help you do this. If your "root" node claims it implements the -interface ``zope.location.interfaces.ILocation``, you don't need to +interface ``repoze.bfg.interfaces.ILocation``, you don't need to manage these attributes by hand. During :term:`traversal`, if the root node says it implements the ``ILocation`` :term:`interface`, :mod:`repoze.bfg` will wrap each child in a ``LocationProxy`` which @@ -84,7 +84,20 @@ recursively. If you choose to make use of the location-based dynamic assignment of ``__parent__`` and ``__name__``, the root node must have a ``__parent__`` and a ``__name__`` that are both ``None``, and it must -provide the ``ILocation`` interface. The easiest way to do this is to -claim that the class representing the root node -``implements(ILocation)``, as above. +provide the ``repoze.bfg.interfaces.ILocation`` interface. The +easiest way to do this is to claim that the class representing the +root node ``implements(ILocation)``: + +.. code-block:: + :linenos: + + from repoze.bfg.interfaces import ILocation + from zope.interface import implements + + class MyRootObject(object): + implements(ILocation) + __parent__ = None + __name__ = '' + + diff --git a/docs/narr/security.rst b/docs/narr/security.rst index 48c88cbde..76f488f43 100644 --- a/docs/narr/security.rst +++ b/docs/narr/security.rst @@ -84,19 +84,17 @@ class: from repoze.bfg.security import Everyone from repoze.bfg.security import Allow - from zope.location.interfaces import ILocation - from zope.location.location import Location class IBlog(Interface): pass - class Blog(dict, Location): + class Blog(dict): __acl__ = [ (Allow, Everyone, 'view'), (Allow, 'group:editors', 'add'), (Allow, 'group:editors', 'edit'), ] - implements(IBlog, ILocation) + implements(IBlog) The above ACL indicates that the ``Everyone`` principal (a special system-defined principal indicating, literally, everyone) is allowed @@ -128,26 +126,44 @@ Location-Awareness ------------------ In order to allow the security machinery to perform ACL inheritance, -model objects should provide *location-awareness*. +model objects must provide *location-awareness*. Providing +location-awareness means two things: the root object in the graph must +have a ``_name__`` and a ``__parent__`` attribute and the root object +must be declared to implement the ``repoze.bfg.interfaces.ILocation`` +interface. For example: -Objects have parents when they define an ``__parent__`` attribute -which points at their parent object. The root object's ``__parent__`` -is ``None``. An object with a ``__parent__`` attribute and a -``__name__`` attribute is said to be *location-aware*. +.. code-block:: + :linenos: + + from repoze.bfg.interfaces import ILocation + from zope.interface import implements + + class Blog(object): + implements(ILocation) + __name__ = '' + __parent__ = None + +An object with a ``__parent__`` attribute and a ``__name__`` attribute +is said to be *location-aware*. Location-aware objects define an +``__parent__`` attribute which points at their parent object. The +root object's ``__parent__`` is ``None``. If the root object in a :mod:`repoze.bfg` application declares that it -implements the ``ILocation`` interface, it is assumed that the objects -in the rest of the model are location-aware. Even if they are not -explictly, if the root object is marked as ``ILocation``, the bfg -framework will wrap each object during traversal in a *location -proxy*, which will wrap each object found during traversal in a proxy -object that has both the ``__name__`` and ``__parent__`` attributes, -but otherwise acts the same as your model object. +implements the ``repoze.bfg.interfaces.ILocation`` interface, it is +assumed that the objects in the rest of the model are location-aware. +If those objects are not explictly location-aware, if the root object +is marked as ``ILocation``, the bfg framework will wrap each object +during traversal in a *location proxy* that has both the ``__name__`` +and ``__parent__`` attributes, but otherwise acts the same as your +model object. You can of course supply ``__name__`` and ``__parent__`` attributes explicitly on all of your model objects, and no location proxying will be performed. +See :ref:`location_module` for documentations of functions which use +location-awareness. + Debugging Security Failures --------------------------- diff --git a/repoze/bfg/interfaces.py b/repoze/bfg/interfaces.py index 7647facb4..16a4a7b21 100644 --- a/repoze/bfg/interfaces.py +++ b/repoze/bfg/interfaces.py @@ -98,3 +98,11 @@ class IWSGIApplicationCreatedEvent(IObjectEvent): configured.""" app = Attribute(u"Published application") + +class ILocation(Interface): + """Objects that have a structural location""" + + __parent__ = Attribute("The parent in the location hierarchy") + + __name__ = Attribute("The name within the parent") + diff --git a/repoze/bfg/location.py b/repoze/bfg/location.py new file mode 100644 index 000000000..11f08faf9 --- /dev/null +++ b/repoze/bfg/location.py @@ -0,0 +1,132 @@ +############################################################################## +# +# Copyright (c) 2003 Zope Corporation and Contributors. +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# +############################################################################## + +"""Location support borrowed from ``zope.location``, but without +``zope.security`` support, which is not 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``. + + ``model1`` is 'inside' ``model2`` if ``model2`` is a `location + ancestor` of ``model1``. It is a location ancestor if its parent + (or one of its parent's parents, etc.) is an ancestor. + """ + while model1 is not None: + if model1 is model2: + return True + model1 = model1.__parent__ + + return False + +def locate(model, parent, name=None): + """ + If ``model`` explicitly provides the + ``repoze.bfg.interfaces.ILocation`` interface, locate ``model`` + directly set ``model`` 's ``__parent__`` attribute to the + ``parent`` object (also a model), and its ``__name__`` to the + supplied ``name`` argument. + + 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. + """ + if ILocation.providedBy(model): + if parent is not model.__parent__ or name != model.__name__: + _locate(model, parent, name) + return model + return LocationProxy(model, parent, name) + +def lineage(model): + """ + Return a generator representing the model lineage. The generator + first returns ``model`` unconditionally. Then, if ``model`` + supplies a ``__parent__`` attribute, return the object represented + by ``model.__parent__``. If *that* object has a ``__parent__`` + attribute, return that object's parent, and so on, until the + object being inspected either has no ``__parent__`` attribute or + which has a ``__parent__`` attribute of ``None``. For example, if + the object tree is:: + + thing1 = Thing() + thing2 = Thing() + thing2.__parent__ = thing1 + + Calling ``lineage(thing2)`` will return a generator. When we turn + it into a list, we will get:: + + list(lineage(thing2)) + [ <Thing object at thing2>, <Thing object at thing1> ] + """ + while model is not None: + yield model + model = getattr(model, '__parent__', None) + +def _locate(model, parent, name=None): + model.__parent__ = parent + model.__name__ = name + +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/security.py b/repoze/bfg/security.py index 6c1f262f1..49f47bc89 100644 --- a/repoze/bfg/security.py +++ b/repoze/bfg/security.py @@ -5,7 +5,7 @@ import sys from zope.interface import implements from zope.component import queryUtility -from zope.location.location import LocationIterator +from repoze.bfg.location import lineage from repoze.bfg.interfaces import ISecurityPolicy from repoze.bfg.interfaces import IViewPermission @@ -109,7 +109,7 @@ class ACLSecurityPolicy(object): """ Return ``Allowed`` if the policy permits access, ``Denied`` if not.""" principals = self.effective_principals(request) - for location in LocationIterator(context): + for location in lineage(context): authorizer = self.authorizer_factory(location, self.logger) try: return authorizer.permits(permission, *principals) @@ -134,7 +134,7 @@ class ACLSecurityPolicy(object): return effective_principals def principals_allowed_by_permission(self, context, permission): - for location in LocationIterator(context): + for location in lineage(context): acl = getattr(location, '__acl__', None) if acl is not None: allowed = {} diff --git a/repoze/bfg/tests/test_location.py b/repoze/bfg/tests/test_location.py new file mode 100644 index 000000000..fc8f8c621 --- /dev/null +++ b/repoze/bfg/tests/test_location.py @@ -0,0 +1,82 @@ +import unittest + +class TestLocation(unittest.TestCase): + def test_inside(self): + o1 = Location() + o2 = Location(); o2.__parent__ = o1 + o3 = Location(); o3.__parent__ = o2 + o4 = Location(); o4.__parent__ = o3 + + from repoze.bfg.location import inside + self.assertEqual(inside(o1, o1), True) + self.assertEqual(inside(o2, o1), True) + self.assertEqual(inside(o3, o1), True) + self.assertEqual(inside(o4, o1), True) + self.assertEqual(inside(o1, o4), False) + self.assertEqual(inside(o1, None), False) + + 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') + self.failUnless(a_located is a) + self.failUnless(a_located.__parent__ is parent) + self.assertEqual(a_located.__name__, 'a') + # If we locate the object again, nothing special happens: + + 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() + o2 = Location(); o2.__parent__ = o1 + o3 = Location(); o3.__parent__ = o2 + o4 = Location(); o4.__parent__ = o3 + result = list(lineage(o3)) + self.assertEqual(result, [o3, o2, o1]) + result = list(lineage(o1)) + self.assertEqual(result, [o1]) + +from repoze.bfg.interfaces import ILocation +from zope.interface import implements +class Location(object): + implements(ILocation) + __name__ = __parent__ = None diff --git a/repoze/bfg/tests/test_traversal.py b/repoze/bfg/tests/test_traversal.py index 8034cf39b..4dced41ca 100644 --- a/repoze/bfg/tests/test_traversal.py +++ b/repoze/bfg/tests/test_traversal.py @@ -112,7 +112,7 @@ class ModelGraphTraverserTests(unittest.TestCase, PlacelessSetup): foo = DummyContext(bar) root = DummyContext(foo) from zope.interface import directlyProvides - from zope.location.interfaces import ILocation + from repoze.bfg.interfaces import ILocation directlyProvides(root, ILocation) root.__name__ = None root.__parent__ = None diff --git a/repoze/bfg/tests/test_zcml.py b/repoze/bfg/tests/test_zcml.py index 158743c64..6d79606ad 100644 --- a/repoze/bfg/tests/test_zcml.py +++ b/repoze/bfg/tests/test_zcml.py @@ -32,7 +32,7 @@ class TestViewDirective(unittest.TestCase, PlacelessSetup): from repoze.bfg.interfaces import IView from repoze.bfg.interfaces import IViewPermission from repoze.bfg.security import ViewPermissionFactory - from zope.component.zcml import handler + from repoze.bfg.zcml import handler from zope.component.interface import provideInterface self.assertEqual(len(actions), 3) @@ -79,7 +79,7 @@ class TestViewDirective(unittest.TestCase, PlacelessSetup): from repoze.bfg.interfaces import IView from repoze.bfg.interfaces import IViewPermission from repoze.bfg.security import ViewPermissionFactory - from zope.component.zcml import handler + from repoze.bfg.zcml import handler from zope.component.interface import provideInterface self.assertEqual(len(actions), 3) @@ -125,7 +125,7 @@ class TestViewDirective(unittest.TestCase, PlacelessSetup): cacheable=False) actions = context.actions from repoze.bfg.interfaces import IView - from zope.component.zcml import handler + from repoze.bfg.zcml import handler from repoze.bfg.zcml import Uncacheable self.assertEqual(len(actions), 3) diff --git a/repoze/bfg/traversal.py b/repoze/bfg/traversal.py index 9783955de..f5d45cd55 100644 --- a/repoze/bfg/traversal.py +++ b/repoze/bfg/traversal.py @@ -3,10 +3,10 @@ import urlparse from zope.interface import classProvides from zope.interface import implements -from zope.location.location import located -from zope.location.location import LocationIterator -from zope.location.interfaces import ILocation +from repoze.bfg.location import locate +from repoze.bfg.location import lineage +from repoze.bfg.interfaces import ILocation from repoze.bfg.interfaces import ITraverser from repoze.bfg.interfaces import ITraverserFactory @@ -60,7 +60,7 @@ class ModelGraphTraverser(object): name = segment break if self.locatable: - next = located(next, ob, segment) + next = locate(next, ob, segment) ob = next return ob, name, path @@ -68,7 +68,7 @@ class ModelGraphTraverser(object): def find_root(model): """ Find the root node in the graph to which ``model`` belongs. Note that ``model`` should be :term:`location`-aware.""" - for location in LocationIterator(model): + for location in lineage(model): if location.__parent__ is None: model = location break @@ -99,7 +99,7 @@ def find_interface(model, interface): ``interface`` in the parent chain of ``model`` or ``None`` if no object providing ``interface`` can be found in the parent chain. The ``model`` passed in should be :term:`location`-aware.""" - for location in LocationIterator(model): + for location in lineage(model): if interface.providedBy(location): return location @@ -112,7 +112,7 @@ def model_url(model, request, *elements): URL-quoted. The ``model`` passed in must be :term:`location`-aware.""" rpath = [] - for location in LocationIterator(model): + for location in lineage(model): if location.__name__: rpath.append(urllib.quote(location.__name__)) path = list(reversed(rpath)) @@ -127,7 +127,7 @@ def model_path(model, *elements): will be joined by slashes and appended to the generated path. The ``model`` passed in must be :term:`location`-aware.""" rpath = [] - for location in LocationIterator(model): + for location in lineage(model): if location.__name__: rpath.append(location.__name__) path = list(reversed(rpath)) diff --git a/repoze/bfg/zcml.py b/repoze/bfg/zcml.py index b5de0584a..a38c39ae1 100644 --- a/repoze/bfg/zcml.py +++ b/repoze/bfg/zcml.py @@ -4,9 +4,11 @@ from os.path import realpath import time from zope.configuration import xmlconfig + +from zope.component import getGlobalSiteManager import zope.configuration.config -from zope.component.zcml import handler + from zope.component.interface import provideInterface from zope.configuration.exceptions import ConfigurationError from zope.configuration.fields import GlobalObject @@ -22,6 +24,10 @@ from repoze.bfg.path import package_path from repoze.bfg.security import ViewPermissionFactory +def handler(methodName, *args, **kwargs): + method = getattr(getGlobalSiteManager(), methodName) + method(*args, **kwargs) + class Uncacheable(object): """ Include in discriminators of actions which are not cacheable """ pass @@ -26,18 +26,18 @@ README = open(os.path.join(here, 'README.txt')).read() CHANGES = open(os.path.join(here, 'CHANGES.txt')).read() install_requires=[ - 'zope.interface', - 'zope.component', - 'zope.testing', - 'zope.hookable', - 'zope.event', - 'WebOb', - 'PasteScript', 'chameleon.core [lxml]', - 'chameleon.zpt', 'chameleon.genshi', + 'chameleon.zpt', + 'PasteScript', 'Routes', 'setuptools', + 'WebOb', + 'zope.component', + 'zope.configuration', + 'zope.hookable', + 'zope.interface', + 'zope.proxy', ] setup(name='repoze.bfg', |
