diff --git a/browser/adding.py b/browser/adding.py index 3a9f978..cd6b2c9 100644 --- a/browser/adding.py +++ b/browser/adding.py @@ -18,6 +18,8 @@ $Id$ """ +__docformat__ = 'restructuredtext' + from warnings import warn import zope.security.checker from zope.interface import implements @@ -200,7 +202,7 @@ def isSingleMenuItem(self): return len(self.addingInfo()) == 1 def hasCustomAddView(self): - "This should be called only if there is singleMenuItem else return 0" + "This should be called only if there is `singleMenuItem` else return 0" if self.isSingleMenuItem(): menu_item = self.addingInfo()[0] if 'has_custom_add_view' in menu_item: diff --git a/browser/contents.py b/browser/contents.py index 77369c7..54eb698 100644 --- a/browser/contents.py +++ b/browser/contents.py @@ -15,6 +15,7 @@ $Id$ """ +__docformat__ = 'restructuredtext' from zope.exceptions import NotFoundError from zope.security.interfaces import Unauthorized @@ -348,7 +349,7 @@ def pasteObjects(self): def hasClipboardContents(self): - """ interogates the PrinicipalAnnotation to see if + """ interogates the `PrinicipalAnnotation` to see if clipboard contents exist """ if not self.supportsPaste: diff --git a/browser/find.py b/browser/find.py index 31df805..36143f6 100644 --- a/browser/find.py +++ b/browser/find.py @@ -15,6 +15,8 @@ $Id$ """ +__docformat__ = 'restructuredtext' + from zope.app.container.find import SimpleIdFindFilter from zope.app.container.interfaces import IFind from zope.app.traversing.api import getName @@ -25,7 +27,7 @@ class Find(BrowserView): def findByIds(self, ids): - """Do a find for the ids listed in ids, which is a string.""" + """Do a find for the `ids` listed in `ids`, which is a string.""" finder = IFind(self.context) ids = ids.split() # if we don't have any ids listed, don't search at all diff --git a/browser/metaconfigure.py b/browser/metaconfigure.py index 2c55f59..b42f654 100644 --- a/browser/metaconfigure.py +++ b/browser/metaconfigure.py @@ -11,11 +11,12 @@ # FOR A PARTICULAR PURPOSE. # ############################################################################## -"""Container-specific ``browser`` ZCML namespace directive handlers +"""Container-specific browser ZCML namespace directive handlers $Id$ """ __docformat__ = 'restructuredtext' + from zope.interface import Interface from zope.configuration.fields import GlobalObject from zope.schema import Id @@ -26,7 +27,7 @@ from zope.app.security.fields import Permission class IContainerViews(Interface): - """Define several container views for an ``IContainer`` implementation.""" + """Define several container views for an `IContainer` implementation.""" for_ = GlobalObject( title=u"The interface this containerViews are for.", diff --git a/btree.py b/btree.py index adda81c..c894827 100644 --- a/btree.py +++ b/btree.py @@ -20,6 +20,7 @@ $Id$ """ +__docformat__ = 'restructuredtext' from persistent import Persistent from BTrees.OOBTree import OOBTree diff --git a/contained.py b/contained.py index e6461d8..e193977 100644 --- a/contained.py +++ b/contained.py @@ -11,10 +11,11 @@ # FOR A PARTICULAR PURPOSE. # ############################################################################## -"""Classes to support implenting IContained +"""Classes to support implenting `IContained` $Id$ """ +__docformat__ = 'restructuredtext' from zope.exceptions import DuplicationError from zope.security.checker import selectChecker, CombinedChecker @@ -39,7 +40,7 @@ from zope.app.container._zope_app_container_contained import getProxiedObject class Contained(object): - """Stupid mix-in that defines __parent__ and __name__ attributes + """Stupid mix-in that defines `__parent__` and `__name__` attributes """ zope.interface.implements(IContained) @@ -210,11 +211,11 @@ def containedEvent(object, container, name=None): """Establish the containment of the object in the container The object and necessary event are returned. The object may be a - ContainedProxy around the original object. The event is an added + `ContainedProxy` around the original object. The event is an added event, a moved event, or None. - If the object implements IContained, simply set its __parent__ - and __name__ attributes: + If the object implements `IContained`, simply set its `__parent__` + and `__name__` attributes: >>> container = {} >>> item = Contained() @@ -270,9 +271,9 @@ def containedEvent(object, container, name=None): >>> event.oldName u'foo' - If the object implements ILocation, but not IContained, set it's - __parent__ and __name__ attributes *and* declare that it - implements IContained: + If the `object` implements `ILocation`, but not `IContained`, set it's + `__parent__` and `__name__` attributes *and* declare that it + implements `IContained`: >>> from zope.app.location import Location >>> item = Location() @@ -289,8 +290,8 @@ def containedEvent(object, container, name=None): True - If the object doesn't even implement ILocation, put a - ContainedProxy around it: + If the `object` doesn't even implement `ILocation`, put a + `ContainedProxy` around it: >>> item = [] >>> x, event = containedEvent(item, container, 'foo') @@ -331,7 +332,7 @@ def contained(object, container, name=None): Just return the contained object without an event. This is a convenience "macro" for: - containedEvent(object, container, name)[0] + ``containedEvent(object, container, name)[0]`` This function is only used for tests. """ @@ -341,10 +342,10 @@ def setitem(container, setitemf, name, object): """Helper function to set an item and generate needed events This helper is needed, in part, because the events need to get - published after the object has been added to the container. + published after the `object` has been added to the `container`. - If the item implements IContained, simply set it's __parent__ - and __name attributes: + If the item implements `IContained`, simply set it's `__parent__` + and `__name__` attributes: >>> class IItem(zope.interface.Interface): ... pass @@ -376,7 +377,7 @@ def setitem(container, setitemf, name, object): >>> item.__name__ u'c' - If we run this using the testing framework, we'll use getEvents to + If we run this using the testing framework, we'll use `getEvents` to track the events generated: >>> from zope.app.event.tests.placelesssetup import getEvents @@ -410,8 +411,8 @@ def setitem(container, setitemf, name, object): >>> item.moved is event 1 - We can suppress events and hooks by setting the __parent__ and - __name__ first: + We can suppress events and hooks by setting the `__parent__` and + `__name__` first: >>> item = Item() >>> item.__parent__, item.__name__ = container, 'c2' @@ -465,9 +466,9 @@ def setitem(container, setitemf, name, object): 3 - If the object implements ILocation, but not IContained, set it's - __parent__ and __name__ attributes *and* declare that it - implements IContained: + If the object implements `ILocation`, but not `IContained`, set it's + `__parent__` and `__name__` attributes *and* declare that it + implements `IContained`: >>> from zope.app.location import Location >>> item = Location() @@ -490,8 +491,8 @@ def setitem(container, setitemf, name, object): >>> len(getEvents(IObjectModifiedEvent)) 4 - If the object doesn't even implement ILocation, put a - ContainedProxy around it: + If the object doesn't even implement `ILocation`, put a + `ContainedProxy` around it: >>> item = [] >>> setitem(container, container.__setitem__, u'i', item) @@ -569,9 +570,10 @@ def setitem(container, setitemf, name, object): fixing_up = False def uncontained(object, container, name=None): - """Clear the containment relationship between the object amd the container + """Clear the containment relationship between the `object` and + the `container' - If we run this using the testing framework, we'll use getEvents to + If we run this using the testing framework, we'll use `getEvents` to track the events generated: >>> from zope.app.event.tests.placelesssetup import getEvents @@ -629,7 +631,7 @@ def uncontained(object, container, name=None): >>> len(getEvents(IObjectModifiedEvent)) 1 - But, if either the name or parent are not None and they are not + But, if either the name or parent are not ``None`` and they are not the container and the old name, we'll get a modified event but not a removed event. diff --git a/dependency.py b/dependency.py index 6bf7338..bac5ecb 100644 --- a/dependency.py +++ b/dependency.py @@ -15,6 +15,7 @@ $Id$ """ +__docformat__ = 'restructuredtext' from zope.app import zapi from zope.app.dependable.interfaces import IDependable, DependencyError diff --git a/directory.py b/directory.py index 6e161d4..d5efc76 100644 --- a/directory.py +++ b/directory.py @@ -14,30 +14,32 @@ This module includes two adapters (adapter factories, really) for providing a file-system representation for containers: -noop - Factory that "adapts" IContainer to IWriteDirectory. +`noop` + Factory that "adapts" `IContainer` to `IWriteDirectory`. This is a lie, since it just returns the original object. -Cloner - An IDirectoryFactory adapter that just clones the original object. +`Cloner` + An `IDirectoryFactory` adapter that just clones the original object. $Id$ """ +__docformat__ = 'restructuredtext' + import zope.app.filerepresentation.interfaces from zope.security.proxy import removeSecurityProxy from zope.interface import implements def noop(container): - """Adapt an IContainer to an IWriteDirectory by just returning it + """Adapt an `IContainer` to an `IWriteDirectory` by just returning it - This "works" because IContainer and IWriteDirectory have the same - methods, however, the output doesn't actually implement IWriteDirectory. + This "works" because `IContainer` and `IWriteDirectory` have the same + methods, however, the output doesn't actually implement `IWriteDirectory`. """ return container class Cloner(object): - """IContainer to IDirectoryFactory adapter that clones + """`IContainer` to `IDirectoryFactory` adapter that clones This adapter provides a factory that creates a new empty container of the same class as it's context. diff --git a/find.py b/find.py new file mode 100644 index 0000000..9f63e3c --- /dev/null +++ b/find.py @@ -0,0 +1,76 @@ +############################################################################## +# +# Copyright (c) 2001, 2002 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. +# +############################################################################## +"""Find Support + +$Id$ +""" +__docformat__ = 'restructuredtext' + +from zope.interface import implements +from interfaces import IFind, IIdFindFilter +from interfaces import IReadContainer + +class FindAdapter(object): + + implements(IFind) + + __used_for__ = IReadContainer + + def __init__(self, context): + self._context = context + + def find(self, id_filters=None, object_filters=None): + 'See IFind' + id_filters = id_filters or [] + object_filters = object_filters or [] + result = [] + container = self._context + for id, object in container.items(): + _find_helper(id, object, container, + id_filters, object_filters, + result) + return result + + +def _find_helper(id, object, container, id_filters, object_filters, result): + for id_filter in id_filters: + if not id_filter.matches(id): + break + else: + # if we didn't break out of the loop, all name filters matched + # now check all object filters + for object_filter in object_filters: + if not object_filter.matches(object): + break + else: + # if we didn't break out of the loop, all filters matched + result.append(object) + + if not IReadContainer.providedBy(object): + return + + container = object + for id, object in container.items(): + _find_helper(id, object, container, id_filters, object_filters, result) + +class SimpleIdFindFilter(object): + + implements(IIdFindFilter) + + def __init__(self, ids): + self._ids = ids + + def matches(self, id): + 'See INameFindFilter' + return id in self._ids diff --git a/interfaces.py b/interfaces.py new file mode 100644 index 0000000..b4b134c --- /dev/null +++ b/interfaces.py @@ -0,0 +1,267 @@ +############################################################################## +# +# 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. +# +############################################################################## +"""Container-related interfaces + +$Id$ +""" +__docformat__ = 'restructuredtext' + +from zope.interface import Interface, Attribute, implements, Invalid +from zope.component.interfaces import IView +from zope.interface.common.mapping import IItemMapping +from zope.interface.common.mapping import IReadMapping, IEnumerableMapping +from zope.app.location.interfaces import ILocation +from zope.app.event.interfaces import IObjectEvent + +class DuplicateIDError(KeyError): + pass + +class ContainerError(Exception): + """An error of a container with one of its components.""" + +class InvalidContainerType(Invalid, TypeError): + """The type of a container is not valid + """ + +class InvalidItemType(Invalid, TypeError): + """The type of an item is not valid + """ + +class InvalidType(Invalid, TypeError): + """The type of an object is not valid + """ + +class IContained(ILocation): + """Objects contained in containers + """ + +class IItemContainer(IItemMapping): + """Minimal readable container + """ + +class ISimpleReadContainer(IItemContainer, IReadMapping): + """Readable content containers + """ + +class IReadContainer(ISimpleReadContainer, IEnumerableMapping): + """Readable containers that can be enumerated. + """ + +class IWriteContainer(Interface): + """An interface for the write aspects of a container.""" + + def __setitem__(name, object): + """Add the given `object` to the container under the given name. + + Raises a ``TypeError`` if the key is not a unicode or ascii string. + Raises a ``ValueError`` if key is empty. + + The container might choose to add a different object than the + one passed to this method. + + If the object doesn't implement `IContained`, then one of two + things must be done: + + 1. If the object implements `ILocation`, then the `IContained` + interface must be declared for the object. + + 2. Otherwise, a `ContainedProxy` is created for the object and + stored. + + The object's `__parent__` and `__name__` attributes are set to the + container and the given name. + + If the old parent was ``None``, then an `IObjectAddedEvent` is + generated, otherwise, and `IObjectMovedEvent` is generated. An + `IObjectModifiedEvent` is generated for the container. If an + add event is generated and the object can be adapted to + `IObjectAddedEvent`, then the adapter's `addNotify` method is called + with the event. If the object can be adapted to + `IObjectMovedEvent`, then the adapter's `moveNotify` method is + called with the event. + + If the object replaces another object, then the old object is + deleted before the new object is added, unless the container + vetos the replacement by raising an exception. + + If the object's `__parent__` and `__name__` were already set to + the container and the name, then no events are generated and + no hooks. This allows advanced clients to take over event + generation. + + """ + + def __delitem__(name): + """Delete the nameed object from the container. + + Raises a ``KeyError`` if the object is not found. + + If the deleted object's `__parent__` and `__name__` match the + container and given name, then an `IObjectRemovedEvent` is + generated and the attributes are set to ``None``. If the object + can be adapted to `IObjectMovedEvent`, then the adapter's + `moveNotify` method is called with the event. + + Unless the object's `__parent__` and `__name__` attributes were + initially ``None``, generate an `IObjectModifiedEvent` for the + container. + + If the object's `__parent__` and `__name__` were already set to + ``None``, then no events are generated. This allows advanced + clients to take over event generation. + + """ + +class IItemWriteContainer(IWriteContainer, IItemContainer): + """A write container that also supports minimal reads.""" + +class IContentContainer(IWriteContainer): + """Containers (like folders) that contain ordinary content""" + +class IContainer(IReadContainer, IWriteContainer): + """Readable and writable content container.""" + +class IOrderedContainer(IContainer): + """Containers whose contents are maintained in order + """ + + def updateOrder(order): + """Revise the order of keys, replacing the current ordering. + + order is a list or a tuple containing the set of existing keys in + the new order. `order` must contain ``len(keys())`` items and cannot + contain duplicate keys. + + Raises ``TypeError`` if order is not a tuple or a list. + + Raises ``ValueError`` if order contains an invalid set of keys. + """ + +class IContainerNamesContainer(IContainer): + """Containers that always choose names for their items + """ + + +############################################################################## +# Moving Objects + +class IObjectMovedEvent(IObjectEvent): + """An object has been moved""" + + oldParent = Attribute("The old location parent for the object.") + oldName = Attribute("The old location name for the object.") + newParent = Attribute("The new location parent for the object.") + newName = Attribute("The new location name for the object.") + +############################################################################## +# Adding objects + +class UnaddableError(ContainerError): + """An object cannot be added to a container.""" + + def __init__(self, container, obj, message=""): + self.container = container + self.obj = obj + self.message = message and ": %s" % message + + def __str__(self): + return ("%(obj)s cannot be added " + "to %(container)s%(message)s" % self.__dict__) + +class IObjectAddedEvent(IObjectMovedEvent): + """An object has been added to a container.""" + +class IAdding(IView): + + def add(content): + """Add content object to container. + + Add using the name in `contentName`. Returns the added object + in the context of its container. + + If `contentName` is already used in container, raises + ``DuplicateIDError``. + """ + + contentName = Attribute( + """The content name, as usually set by the Adder traverser. + + If the content name hasn't been defined yet, returns ``None``. + + Some creation views might use this to optionally display the + name on forms. + """ + ) + + def nextURL(): + """Return the URL that the creation view should redirect to. + + This is called by the creation view after calling add. + + It is the adder's responsibility, not the creation view's to + decide what page to display after content is added. + """ + + def nameAllowed(): + """Return whether names can be input by the user.""" + + + +class INameChooser(Interface): + + def checkName(name, object): + """Check whether an object name is valid. + + Raise a user error if the name is not valid. + """ + + def chooseName(name, object): + """Choose a unique valid name for the object + + The given name and object may be taken into account when + choosing the name. + + """ + +############################################################################## +# Removing objects + + +class IObjectRemovedEvent(IObjectMovedEvent): + """An object has been removed from a container""" + +############################################################################## +# Finding objects + +class IFind(Interface): + """ + Find support for containers. + """ + + def find(id_filters=None, object_filters=None): + """Find object that matches all filters in all sub objects, + not including this container itself. + """ + +class IObjectFindFilter(Interface): + + def matches(object): + """Returns true if the object matches the filter criteria. + """ + +class IIdFindFilter(Interface): + + def matches(id): + """Returns true if the id matches the filter criteria. + """ diff --git a/ordered.py b/ordered.py new file mode 100644 index 0000000..0a74757 --- /dev/null +++ b/ordered.py @@ -0,0 +1,298 @@ +############################################################################## +# +# Copyright (c) 2001, 2002 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. +# +############################################################################## +"""Ordered container implementation. + +$Id$ +""" +__docformat__ = 'restructuredtext' + +from zope.app.container.interfaces import IOrderedContainer +from zope.interface import implements +from persistent import Persistent +from persistent.dict import PersistentDict +from persistent.list import PersistentList +from types import StringTypes, TupleType, ListType +from zope.app.container.contained import Contained, setitem, uncontained + +class OrderedContainer(Persistent, Contained): + """ `OrderedContainer` maintains entries' order as added and moved. + + >>> oc = OrderedContainer() + >>> int(IOrderedContainer.providedBy(oc)) + 1 + >>> len(oc) + 0 + """ + + implements(IOrderedContainer) + + def __init__(self): + + self._data = PersistentDict() + self._order = PersistentList() + + def keys(self): + """ See `IOrderedContainer`. + + >>> oc = OrderedContainer() + >>> oc.keys() + [] + >>> oc['foo'] = 'bar' + >>> oc.keys() + ['foo'] + >>> oc['baz'] = 'quux' + >>> oc.keys() + ['foo', 'baz'] + >>> int(len(oc._order) == len(oc._data)) + 1 + """ + + return self._order[:] + + def __iter__(self): + """ See `IOrderedContainer`. + + >>> oc = OrderedContainer() + >>> oc.keys() + [] + >>> oc['foo'] = 'bar' + >>> oc['baz'] = 'quux' + >>> [i for i in oc] + ['foo', 'baz'] + >>> int(len(oc._order) == len(oc._data)) + 1 + """ + + return iter(self.keys()) + + def __getitem__(self, key): + """ See `IOrderedContainer`. + + >>> oc = OrderedContainer() + >>> oc['foo'] = 'bar' + >>> oc['foo'] + 'bar' + """ + + return self._data[key] + + def get(self, key, default=None): + """ See `IOrderedContainer`. + + >>> oc = OrderedContainer() + >>> oc['foo'] = 'bar' + >>> oc.get('foo') + 'bar' + >>> oc.get('funky', 'No chance, dude.') + 'No chance, dude.' + """ + + return self._data.get(key, default) + + def values(self): + """ See `IOrderedContainer`. + + >>> oc = OrderedContainer() + >>> oc.keys() + [] + >>> oc['foo'] = 'bar' + >>> oc.values() + ['bar'] + >>> oc['baz'] = 'quux' + >>> oc.values() + ['bar', 'quux'] + >>> int(len(oc._order) == len(oc._data)) + 1 + """ + + return [self._data[i] for i in self._order] + + def __len__(self): + """ See `IOrderedContainer`. + + >>> oc = OrderedContainer() + >>> int(len(oc) == 0) + 1 + >>> oc['foo'] = 'bar' + >>> int(len(oc) == 1) + 1 + """ + + return len(self._data) + + def items(self): + """ See `IOrderedContainer`. + + >>> oc = OrderedContainer() + >>> oc.keys() + [] + >>> oc['foo'] = 'bar' + >>> oc.items() + [('foo', 'bar')] + >>> oc['baz'] = 'quux' + >>> oc.items() + [('foo', 'bar'), ('baz', 'quux')] + >>> int(len(oc._order) == len(oc._data)) + 1 + """ + + return [(i, self._data[i]) for i in self._order] + + def __contains__(self, key): + """ See `IOrderedContainer`. + + >>> oc = OrderedContainer() + >>> oc['foo'] = 'bar' + >>> int('foo' in oc) + 1 + >>> int('quux' in oc) + 0 + """ + + return self._data.has_key(key) + + has_key = __contains__ + + def __setitem__(self, key, object): + """ See `IOrderedContainer`. + + >>> oc = OrderedContainer() + >>> oc.keys() + [] + >>> oc['foo'] = 'bar' + >>> oc._order + ['foo'] + >>> oc['baz'] = 'quux' + >>> oc._order + ['foo', 'baz'] + >>> int(len(oc._order) == len(oc._data)) + 1 + """ + + existed = self._data.has_key(key) + + bad = False + if isinstance(key, StringTypes): + try: + unicode(key) + except UnicodeError: + bad = True + else: + bad = True + if bad: + raise TypeError("'%s' is invalid, the key must be an " + "ascii or unicode string" % key) + if len(key) == 0: + raise ValueError("The key cannot be an empty string") + + setitem(self, self._data.__setitem__, key, object) + + if not existed: + self._order.append(key) + + return key + + def __delitem__(self, key): + """ See `IOrderedContainer`. + + >>> oc = OrderedContainer() + >>> oc.keys() + [] + >>> oc['foo'] = 'bar' + >>> oc['baz'] = 'quux' + >>> oc['zork'] = 'grue' + >>> oc.items() + [('foo', 'bar'), ('baz', 'quux'), ('zork', 'grue')] + >>> int(len(oc._order) == len(oc._data)) + 1 + >>> del oc['baz'] + >>> oc.items() + [('foo', 'bar'), ('zork', 'grue')] + >>> int(len(oc._order) == len(oc._data)) + 1 + """ + + uncontained(self._data[key], self, key) + del self._data[key] + self._order.remove(key) + + def updateOrder(self, order): + """ See `IOrderedContainer`. + + >>> oc = OrderedContainer() + >>> oc['foo'] = 'bar' + >>> oc['baz'] = 'quux' + >>> oc['zork'] = 'grue' + >>> oc.keys() + ['foo', 'baz', 'zork'] + >>> oc.updateOrder(['baz', 'foo', 'zork']) + >>> oc.keys() + ['baz', 'foo', 'zork'] + >>> oc.updateOrder(['baz', 'zork', 'foo']) + >>> oc.keys() + ['baz', 'zork', 'foo'] + >>> oc.updateOrder(['baz', 'zork', 'foo']) + >>> oc.keys() + ['baz', 'zork', 'foo'] + >>> oc.updateOrder(('zork', 'foo', 'baz')) + >>> oc.keys() + ['zork', 'foo', 'baz'] + >>> oc.updateOrder(['baz', 'zork']) + Traceback (most recent call last): + ... + ValueError: Incompatible key set. + >>> oc.updateOrder(['foo', 'bar', 'baz', 'quux']) + Traceback (most recent call last): + ... + ValueError: Incompatible key set. + >>> oc.updateOrder(1) + Traceback (most recent call last): + ... + TypeError: order must be a tuple or a list. + >>> oc.updateOrder('bar') + Traceback (most recent call last): + ... + TypeError: order must be a tuple or a list. + >>> oc.updateOrder(['baz', 'zork', 'quux']) + Traceback (most recent call last): + ... + ValueError: Incompatible key set. + >>> del oc['baz'] + >>> del oc['zork'] + >>> del oc['foo'] + >>> len(oc) + 0 + """ + + if not isinstance(order, ListType) and \ + not isinstance(order, TupleType): + raise TypeError('order must be a tuple or a list.') + + if len(order) != len(self._order): + raise ValueError("Incompatible key set.") + + was_dict = {} + will_be_dict = {} + new_order = PersistentList() + + for i in range(len(order)): + was_dict[self._order[i]] = 1 + will_be_dict[order[i]] = 1 + new_order.append(order[i]) + + if will_be_dict != was_dict: + raise ValueError("Incompatible key set.") + + self._order = new_order + diff --git a/sample.py b/sample.py new file mode 100644 index 0000000..3da41fe --- /dev/null +++ b/sample.py @@ -0,0 +1,90 @@ +############################################################################## +# +# Copyright (c) 2001, 2002 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. +# +############################################################################## +"""Sample container implementation. + +This is primarily for testing purposes. + +It might be useful as a mix-in for some classes, but many classes will +need a very different implementation. + +$Id$ +""" +__docformat__ = 'restructuredtext' + +from zope.app.container.interfaces import IContainer +from zope.interface import implements +from zope.app.container.contained import Contained, setitem, uncontained + +class SampleContainer(Contained): + """Sample container implementation suitable for testing. + + It is not suitable, directly as a base class unless the subclass + overrides `_newContainerData` to return a persistent mapping object. + """ + implements(IContainer) + + def __init__(self): + self.__data = self._newContainerData() + + def _newContainerData(self): + """Construct an item-data container + + Subclasses should override this if they want different data. + + The value returned is a mapping object that also has `get`, + `has_key`, `keys`, `items`, and `values` methods. + """ + return {} + + def keys(self): + '''See interface `IReadContainer`''' + return self.__data.keys() + + def __iter__(self): + return iter(self.__data) + + def __getitem__(self, key): + '''See interface `IReadContainer`''' + return self.__data[key] + + def get(self, key, default=None): + '''See interface `IReadContainer`''' + return self.__data.get(key, default) + + def values(self): + '''See interface `IReadContainer`''' + return self.__data.values() + + def __len__(self): + '''See interface `IReadContainer`''' + return len(self.__data) + + def items(self): + '''See interface `IReadContainer`''' + return self.__data.items() + + def __contains__(self, key): + '''See interface `IReadContainer`''' + return self.__data.has_key(key) + + has_key = __contains__ + + def __setitem__(self, key, object): + '''See interface `IWriteContainer`''' + setitem(self, self.__data.__setitem__, key, object) + + def __delitem__(self, key): + '''See interface `IWriteContainer`''' + uncontained(self.__data[key], self, key) + del self.__data[key] diff --git a/size.py b/size.py index 5d2686b..76719fd 100644 --- a/size.py +++ b/size.py @@ -16,6 +16,8 @@ $Id$ """ +__docformat__ = 'restructuredtext' + from zope.app.i18n import ZopeMessageIDFactory as _ from zope.app.size.interfaces import ISized from zope.interface import implements @@ -28,11 +30,11 @@ def __init__(self, container): self._container = container def sizeForSorting(self): - """See ISized""" + """See `ISized`""" return ('item', len(self._container)) def sizeForDisplay(self): - """See ISized""" + """See `ISized`""" num_items = len(self._container) if num_items == 1: return _('1 item')