[Zope3-checkins] CVS: Zope3/src/zope/app/interfaces -
container.py:1.4
Jim Fulton
jim at zope.com
Sun Sep 21 13:32:21 EDT 2003
Update of /cvs-repository/Zope3/src/zope/app/interfaces
In directory cvs.zope.org:/tmp/cvs-serv14207/src/zope/app/interfaces
Modified Files:
container.py
Log Message:
Greatly expanded the responsibilities of write containers.
Moved location-relevent events here.
Changed to use __setitem__ rather than setObject
Reorganized to group facilities for moving, adding and removing.
Got rid of the zope container interfaces.
=== Zope3/src/zope/app/interfaces/container.py 1.3 => 1.4 ===
--- Zope3/src/zope/app/interfaces/container.py:1.3 Fri Sep 5 14:52:40 2003
+++ Zope3/src/zope/app/interfaces/container.py Sun Sep 21 13:32:20 2003
@@ -16,10 +16,12 @@
$Id$
"""
-from zope.interface import Interface, Attribute
+from zope.interface import Interface, Attribute, implements
from zope.component.interfaces import IView
from zope.interface.common.mapping import IItemMapping
from zope.interface.common.mapping import IReadMapping, IEnumerableMapping
+from zope.app.interfaces.location import ILocation
+from zope.app.interfaces.event import IObjectEvent
class DuplicateIDError(KeyError):
pass
@@ -27,42 +29,10 @@
class ContainerError(Exception):
"""An error of a container with one of its components."""
-class CopyException(Exception):
- """An error that occurred within a copy operation."""
-
- def __init__(self, container, key, message=""):
- self.container = container
- self.key = key
- self.message = message and ": %s" % message
-
- def __str__(self):
- return ("%(key)s cannot be copied "
- "from %(container)s%(message)s" % self.__dict__)
-
-class MoveException(Exception):
- """An error that occurred within a move operation."""
-
- def __init__(self, container, key, message=""):
- self.container = container
- self.key = key
- self.message = message and ": %s" % message
-
- def __str__(self):
- return ("%(key)s cannot be copied "
- "from %(container)s%(message)s" % self.__dict__)
-
-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 IContained(ILocation):
+ """Objects contained in containers
+ """
class IItemContainer(IItemMapping):
"""Minimal readable container
@@ -79,24 +49,66 @@
class IWriteContainer(Interface):
"""An interface for the write aspects of a container."""
- def setObject(key, object):
- """Add the given object to the container under the given key.
+ 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.
+ one passed to this method.
- Raises a ValueError if key is an empty string, unless the
- container chooses a different key.
+ If the object doesn't implement IContained, then one of two
+ things must be done:
- Raises a TypeError if the key is not a unicode or ascii string.
+ 1. If the object implements ILocation, then the IContained
+ interface must be declared for the object.
- Returns the key used, which might be different than the given key.
+ 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
+ IAddNotifiable, then the adapter's addNotify method is called
+ with the event. If the object can be adapted to
+ IMoveNotifiable, 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__(key):
- """Delete the keyed object from the container.
+ 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 IMoveNotifiable, 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):
@@ -124,14 +136,59 @@
Raises ValueError if order contains an invalid set of keys.
"""
-class IOptionalNamesContainer(IContainer):
- """Containers that will choose names for their items if no names are given
- """
-
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.")
+
+class IMoveNotifiable(Interface):
+ """Interface for notification of being deleted, added, or moved."""
+
+ def moveNotify(event):
+ """Notify of a move event
+
+ This is called after the object has been added to the new
+ location and before it has been deleted from the old.
+
+ """
+
+
+##############################################################################
+# 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 IAddNotifiable(Interface):
+ """Interface for notification of being added."""
+
+ def addNotify(event):
+ """Hook method will call after an object is added to container.
+ """
+
class IAdding(IView):
def add(content):
@@ -163,211 +220,39 @@
decide what page to display after content is added.
"""
-class IZopeItemContainer(IItemContainer):
+class INameChooser(Interface):
- def __getitem__(key):
- """Return the content for the given key
+ def checkName(name, object):
+ """Check whether an object name is valid.
- Raises KeyError if the content can't be found.
-
- The returned value will be in the context of the container.
+ Raise a user error if the name is not valid.
"""
-class IZopeSimpleReadContainer(IZopeItemContainer, ISimpleReadContainer):
- """Readable content containers
- """
+ def chooseName(name, object):
+ """Choose a unique valid name for the object
- def get(key, default=None):
- """Get a value for a key
+ The given name and object may be taken into account when
+ choosing the name.
- The default is returned if there is no value for the key.
-
- The value for the key will be in the context of the container.
- """
-
-class IZopeReadContainer(IZopeSimpleReadContainer, IReadContainer):
- """Readable containers that can be enumerated.
- """
-
- def values():
- """Return the values of the mapping object in the context of
- the container
- """
-
- def items():
- """Return the items of the mapping object in the context
- of the container
"""
+##############################################################################
+# Removing objects
-class IZopeWriteContainer(IWriteContainer):
- """An interface for the write aspects of a container."""
-
- def setObject(key, object):
- """Add the given object to the container under the given key.
-
- Raises a ValueError if key is an empty string, unless the
- context wrapper chooses a different key.
-
- Returns the key used, which might be different than the given key.
-
- If the object has an adpter to IAddNotifiable then the afterAddHook
- method on the adpter will be called after the object is added.
-
- An IObjectAddedEvent will be published after the object is added and
- after afterAddHook is called. The event object will be the added
- object in the context of the container
-
- An IObjectModifiedEvent will be published after the IObjectAddedEvent
- is published. The event object will be the container.
- """
- def __delitem__(key):
- """Delete the keyed object from the context of the container.
+class IObjectRemovedEvent(IObjectMovedEvent):
+ """An object has been removed from a container"""
- Raises a KeyError if the object is not found.
-
- If the object has an adpter to IDeleteNotifiable then the
- beforeDeleteHook method on the adpter will be called before
- the object is removed.
-
- An IObjectRemovedEvent will be published before the object is
- removed and before beforeDeleteHook method is called.
- The event object will be the removed from the context of the container
-
- An IObjectModifiedEvent will be published after the
- IObjectRemovedEvent is published. The event object will be the
- container.
- """
-
-class IZopeItemWriteContainer(IZopeWriteContainer, IZopeItemContainer):
- """An IZopeWriteContainer for writable item containers.
-
- 'setObject' and '__delitem__' of IZopeWriteContainer imply being able
- to get at an object after it has been added to the container, or
- before it has been deleted from the container.
- This interface makes that contract explicit, and also offers to
- make '__getitem__' context-aware.
- """
-
-class IZopeContainer(IZopeReadContainer, IZopeWriteContainer, IContainer):
- """Readable and writable content container."""
-
-class IAddNotifiable(Interface):
- """Interface for notification of being added."""
-
- def afterAddHook(object, container):
- """Hook method will call after an object is added to container."""
-
-class IDeleteNotifiable(Interface):
+class IRemoveNotifiable(Interface):
"""Interface for notification of being deleted."""
- def beforeDeleteHook(object, container):
+ def removeNotify(object, container):
"""Hook method will call before object is removed from container."""
-class IMoveNotifiable(IDeleteNotifiable, IAddNotifiable):
- """Interface for notification of being deleted, added, or moved."""
-
- def beforeDeleteHook(object, container, movingTo=None):
- """Hook method will call before object is removed from container.
-
- If the object is being moved, 'movingTo' will be the unicode path
- the object is being moved to.
- If the object is simply being deleted and not being moved, 'movingTo'
- will be None.
- """
-
- def afterAddHook(object, container, movedFrom=None):
- """Hook method will call after an object is added to container.
-
- If the object is being moved, 'movedFrom' will be the unicode path
- the object was moved from.
- If the object is simply being added and not being moved, 'movedFrom'
- will be None.
- """
-
-class ICopyNotifiable(IAddNotifiable):
-
- def afterAddHook(object, container, copiedFrom=None):
- """Hook method. Will be called after an object is added to a
- container.
-
- If the object is being copied, 'copiedFrom' will
- be the unicode path the object was copied from.
-
- If the object is simply being added and not being copied,
- 'copiedFrom' will be None.
-
- Clients calling this method must be careful to use
- 'copiededFrom' as a keyword argument rather than a positional
- argument, to avoid confusion if the object is both
- IMoveNotifiable and ICopyNotifiable. """
-
-class IPasteTarget(Interface):
-
- def acceptsObject(key, obj):
- '''Allow the container to say if it accepts the given wrapped
- object.
-
- Returns True if the object would be accepted as contents of
- this container. Otherwise, returns False.
- '''
-
- def pasteObject(key, obj):
- '''Add the given object to the container under the given key.
-
- Raises a ValueError if key is an empty string, unless the
- this object chooses a different key.
-
- Returns the key used, which might be different than the
- given key.
-
- This method must not issue an IObjectAddedEvent, nor must it
- call the afterAddHook hook of the object.
- However, it must publish an IObjectModified event for the
- container.
- '''
-
-class IMoveSource(Interface):
-
- def removeObject(key, movingTo):
- '''Remove and return the object with the given key, as the
- first part of a move.
-
- movingTo is the unicode path for where the move is to.
- This method should not publish an IObjectRemovedEvent, nor should
- it call the afterDeleteHook method of the object.
- However, it must publish an IObjectModified event for the container.
- '''
-
-class ICopySource(Interface):
-
- def copyObject(key, copyingTo):
- '''Return the object with the given key, as the first part of a
- copy.
-
- copyingTo is the unicode path for where the copy is to.
- '''
-
-class INoChildrenCopySource(ICopySource):
-
- def copyObjectWithoutChildren(key, copyingTo):
- '''Return the object with the given key, without any children,
- as the first part of a copy.
-
- copyingTo is the unicode path for where the copy is to.
-
- May return None if its not possible to get a copy without children.
- '''
-
-class IPasteNamesChooser(Interface):
- """Containers automatically chooses a new name for the object if the
- given one is already choosen.
- """
-
- def getNewName(obj, key):
- """ Should return a choosen name based on object and key to be used
- for pasting. This may not be reliable all the time as
- the name you choose is not guaranteed to be reserved between the time
- you get it and the time you paste the object, so be careful."""
+##############################################################################
+# Backward compatability
+from zope.app.interfaces import event
+event.IObjectMovedEvent = IObjectMovedEvent
+event.IObjectAddedEvent = IObjectAddedEvent
+event.IObjectRemovedEvent = IObjectRemovedEvent
More information about the Zope3-Checkins
mailing list