[Zope3-checkins] CVS: Zope3/src/zope/app/container - add.py:1.1.2.1
contained.py:1.1.2.1 remove.py:1.1.2.1
configure.zcml:1.18.2.1 copypastemove.py:1.10.24.1
find.py:1.7.2.1 ordered.py:1.5.10.1 sample.py:1.7.24.1
zopecontainer.py:NONE
Jim Fulton
jim at zope.com
Mon Sep 8 15:22:21 EDT 2003
Update of /cvs-repository/Zope3/src/zope/app/container
In directory cvs.zope.org:/tmp/cvs-serv20092/src/zope/app/container
Modified Files:
Tag: parentgeddon-branch
configure.zcml copypastemove.py find.py ordered.py sample.py
Added Files:
Tag: parentgeddon-branch
add.py contained.py remove.py
Removed Files:
Tag: parentgeddon-branch
zopecontainer.py
Log Message:
Checking in work in progress on parentgeddon-branch so Fred can help
me to get the tests passing. Specific log entries will be provided
when we merge this into the head.
=== Added File Zope3/src/zope/app/container/add.py ===
##############################################################################
#
# Copyright (c) 2003 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (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.
#
##############################################################################
"""Object adding support
This module provides an IAddTarget implementation. Add targets are
helper adapters that help satisfy framework-defined constraints when
additing objects:
- If an object is add notifiable, call the after add hook.
- Generate an ObjectAdded event for the object added.
- Generate an ObjectModified event for the container.
Notes:
- We really should get rid of the hooks and handle them via
subscriptions.
- Other frameworks might impose different constraints, which is
why this functionality of provided via adaptation rather than
fixed apis.
$Id: add.py,v 1.1.2.1 2003/09/08 18:21:19 jim Exp $
"""
import zope.interface
from zope.exceptions import DuplicationError
from zope.app.interfaces import container
from zope.app import zapi
from zope.app.event import objectevent, publish
from zope.app.interfaces.container import IAddNotifiable
from zope.proxy import removeAllProxies
class AddTarget:
"""Adapter that helps when adding objects.
"""
zope.interface.implements(container.IAddTarget)
def __init__(self, context):
self.context = context
def acceptsObject(self, name, obj):
"""Check that an object can be added to a container
>>> class Sample(dict):
... def setObject(self, name, value):
... self[name] = value
... return name
>>> sample = Sample()
>>> target = AddTarget(sample)
We require unicode names or string names that can be converted
to unicode.
>>> target.acceptsObject(u'bob', 1)
1
>>> target.acceptsObject('bob', 1)
1
>>> target.acceptsObject('bob\200', 1)
0
>>> target.acceptsObject(1, 1)
0
We don't allow empty names, or names starting with '@' or '+':
>>> target.acceptsObject('', 1)
0
>>> target.acceptsObject('@@bob', 1)
0
>>> target.acceptsObject('+bob', 1)
0
Or names containing /s:
>>> target.acceptsObject('bill/ted', 1)
0
We also require names to be new:
>>> x = sample.setObject('bob', 1)
>>> target.acceptsObject(u'bob', 1)
0
"""
if not name:
return False
if isinstance(name, str):
try: name = unicode(name)
except UnicodeError:
return False
elif not isinstance(name, unicode):
return False
if name[:1] in '+@' or '/' in name:
return False
if name in self.context:
return False
return True
def addObject(self, name, obj):
"""Add an object
Let's look at an example:
>>> class SampleContainer(dict):
... def setObject(self, name, value):
... self[name] = value
... return name
>>> container = SampleContainer()
>>> class SampleItem:
... zope.interface.implements(IAddNotifiable)
... def afterAddHook(self, object, container):
... self.hookargs = object, container
>>> import zope.app.tests.placelesssetup
>>> from zope.app.event.tests.placelesssetup import getEvents
>>> zope.app.tests.placelesssetup.setUp()
>>> target = AddTarget(container)
>>> item = SampleItem()
We'll get an error if we give an invalid name:
>>> target.addObject(1, item)
Traceback (most recent call last):
...
ValueError: Invalid name
and won't get any events:
>>> getEvents()
[]
But, if we use a valid name:
>>> target.addObject('bob', item)
'bob'
We'll get an add event and a modification event generated:
>>> len(getEvents())
2
>>> from zope.app.interfaces.event import IObjectAddedEvent
>>> getEvents(IObjectAddedEvent)[0].object is item
1
>>> from zope.app.interfaces.event import IObjectModifiedEvent
>>> getEvents(IObjectModifiedEvent)[0].object is container
1
The hook method on the item was also called:
>>> item.hookargs == (item, container)
1
>>> zope.app.tests.placelesssetup.tearDown()
"""
if not self.acceptsObject(name, obj):
raise ValueError("Invalid name")
container = self.context
# We remove the proxies from the object before adding it to
# the container, because we can't store proxies.
obj = removeAllProxies(obj)
# Add the object
name = container.setObject(name, obj)
# Publish an added event
# We explicitly get the object back from the container with
# container[name], because some kinds of container may choose
# to store a different object than the exact one we added.
publish(container, objectevent.ObjectAddedEvent(obj))
# Call the after add hook, if necessary
adapter = zapi.queryAdapter(obj, IAddNotifiable)
if adapter is not None:
adapter.afterAddHook(obj, container)
publish(container, objectevent.ObjectModifiedEvent(container))
return name
=== Added File Zope3/src/zope/app/container/contained.py ===
##############################################################################
#
# Copyright (c) 2003 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (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.
#
##############################################################################
"""Classes to support implenting IContained
$Id: contained.py,v 1.1.2.1 2003/09/08 18:21:19 jim Exp $
"""
import zope.interface
from zope.app.interfaces.container import IContained
from zope.app.interfaces.location import ILocation
from zope.proxy import ProxyBase, getProxiedObject
from zope.app.decorator import DecoratorSpecificationDescriptor
from zope.app.decorator import DecoratedSecurityCheckerDescriptor
class Contained(object):
"""Stupid mix-in that defines __parent__ and __name__ attributes
"""
zope.interface.implements(IContained)
__parent__ = __name__ = None
def contained(object, container, name=None):
"""Establish the containment of the object in the container
If the object implements IContained, simply set it's __parent__
and __name attributes:
>>> container = {}
>>> item = Contained()
>>> x = contained(item, container, 'foo')
>>> x is item
1
>>> item.__parent__ is container
1
>>> item.__name__
'foo'
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()
>>> IContained.isImplementedBy(item)
0
>>> x = contained(item, container, 'foo')
>>> x is item
1
>>> item.__parent__ is container
1
>>> item.__name__
'foo'
>>> IContained.isImplementedBy(item)
1
If the object doesn't even implement ILocation, put a
ContainedProxy around it:
>>> item = []
>>> x = contained(item, container, 'foo')
>>> x is item
0
>>> x.__parent__ is container
1
>>> x.__name__
'foo'
"""
if not IContained.isImplementedBy(object):
if ILocation.isImplementedBy(object):
zope.interface.directlyProvides(object, IContained)
else:
object = ContainedProxy(object)
object.__parent__ = container
object.__name__ = name
return object
def uncontained(object):
"""Clear the containment relationship between the object amd the container
>>> container = {}
>>> item = Contained()
>>> x = contained(item, container, 'foo')
>>> x is item
1
>>> item.__parent__ is container
1
>>> item.__name__
'foo'
>>> x = uncontained(item)
>>> item.__parent__ is container
False
>>> item.__name__
"""
object.__parent__ = object.__name__ = None
class ContainedProxy(ProxyBase):
"""Contained-object proxy
This is a picklable proxy that can be put around objects that
don't implemeny IContained.
>>> l = [1, 2, 3]
>>> p = ContainedProxy(l, "Dad", "p")
>>> p
[1, 2, 3]
>>> p.__parent__
'Dad'
>>> p.__name__
'p'
>>> import pickle
>>> p2 = pickle.loads(pickle.dumps(p))
>>> p2
[1, 2, 3]
>>> p2.__parent__
'Dad'
>>> p2.__name__
'p'
"""
zope.interface.implements(IContained)
__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
def __reduce__(self, proto=None):
return (ContainedProxy,
(getProxiedObject(self),
self.__parent__, self.__name__),
)
__reduce_ex__ = __reduce__
__providedBy__ = DecoratorSpecificationDescriptor()
__Security_checker__ = DecoratedSecurityCheckerDescriptor()
def _p_oid(self):
# I'm not persistent, Dagnabit.
raise AttributeError, '_p_oid'
_p_oid = property(_p_oid)
=== Added File Zope3/src/zope/app/container/remove.py ===
##############################################################################
#
# Copyright (c) 2003 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (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.
#
##############################################################################
"""Object removing support
This module provides an IAddSource implementation. Remove sources are
helper adapters that help satisfy framework-defined constraints when
removing objects:
- If an object is delete notifiable, call the before delete hook.
- Generate an ObjectRemoved event for the object removed.
- Generate an ObjectModified event for the container.
Notes:
- We really should get rid of the hooks and handle them via
subscriptions.
- Other frameworks might impose different constraints, which is
why this functionality of provided via adaptation rather than
fixed apis.
$Id: remove.py,v 1.1.2.1 2003/09/08 18:21:19 jim Exp $
"""
import zope.interface
from zope.app.interfaces import container
from zope.app import zapi
from zope.app.event import objectevent, publish
from zope.app.interfaces.container import IDeleteNotifiable
class RemoveSource:
"""Adapter that helps when removing objects.
"""
zope.interface.implements(container.IRemoveSource)
def __init__(self, context):
self.context = context
def removeObject(self, key):
"""Remove an object
Let's look at an example:
>>> class SampleItem:
... zope.interface.implements(IDeleteNotifiable)
... def beforeDeleteHook(self, object, container):
... self.hookargs = object, container
>>> import zope.app.tests.placelesssetup
>>> from zope.app.event.tests.placelesssetup import getEvents
>>> zope.app.tests.placelesssetup.setUp()
>>> item = SampleItem()
>>> container = {'bob': item}
>>> source = RemoveSource(container)
We'll get an error if we give an invalid name:
>>> source.removeObject('bob') is item
1
>>> container
{}
We'll get an removed event and a modification event generated:
>>> len(getEvents())
2
>>> from zope.app.interfaces.event import IObjectRemovedEvent
>>> getEvents(IObjectRemovedEvent)[0].object is item
1
>>> from zope.app.interfaces.event import IObjectModifiedEvent
>>> getEvents(IObjectModifiedEvent)[0].object is container
1
The hook method on the item was also called:
>>> item.hookargs == (item, container)
1
>>> zope.app.tests.placelesssetup.tearDown()
"""
container = self.context
object = container[key]
# Call the before delete hook, if necessary
adapter = zapi.queryAdapter(object, IDeleteNotifiable)
if adapter is not None:
adapter.beforeDeleteHook(object, container)
publish(container, objectevent.ObjectRemovedEvent(object))
del container[key]
publish(container, objectevent.ObjectModifiedEvent(container))
return object
=== Zope3/src/zope/app/container/configure.zcml 1.18 => 1.18.2.1 ===
--- Zope3/src/zope/app/container/configure.zcml:1.18 Fri Sep 5 14:43:20 2003
+++ Zope3/src/zope/app/container/configure.zcml Mon Sep 8 14:21:19 2003
@@ -31,50 +31,23 @@
for="zope.app.interfaces.container.IReadContainer"
/>
- <!-- Decorators for different flavours of container -->
- <adapter
- factory="zope.app.container.zopecontainer.ZopeItemContainerDecorator"
- provides="zope.app.interfaces.context.IZopeContextWrapper"
- for="zope.app.interfaces.container.IItemContainer"
- />
- <adapter
- factory="
- zope.app.container.zopecontainer.ZopeSimpleReadContainerDecorator"
- provides="zope.app.interfaces.context.IZopeContextWrapper"
- for="zope.app.interfaces.container.ISimpleReadContainer"
- />
+
<adapter
- factory="
- zope.app.container.zopecontainer.ZopeReadContainerDecorator"
- provides="zope.app.interfaces.context.IZopeContextWrapper"
+ factory="zope.app.container.size.ContainerSized"
+ provides="zope.app.interfaces.size.ISized"
for="zope.app.interfaces.container.IReadContainer"
/>
+
<adapter
- factory="
- zope.app.container.zopecontainer.ZopeItemWriteContainerDecorator"
- provides="zope.app.interfaces.context.IZopeContextWrapper"
- for="zope.app.interfaces.container.IItemWriteContainer"
- />
- <adapter
- factory="zope.app.container.zopecontainer.ZopeContainerDecorator"
- provides="zope.app.interfaces.context.IZopeContextWrapper"
+ provides="zope.app.interfaces.container.IAddTarget"
for="zope.app.interfaces.container.IContainer"
+ factory=".add.AddTarget"
/>
- <!-- XXX There is a sticky question of what permission 'rename' should have.
- See src/zope/app/context.txt for further discussion.
- -->
- <class class="zope.app.container.zopecontainer.ZopeContainerDecorator">
- <require
- attributes="rename"
- permission="zope.ManageServices"
- />
- </class>
-
<adapter
- factory="zope.app.container.size.ContainerSized"
- provides="zope.app.interfaces.size.ISized"
- for="zope.app.interfaces.container.IReadContainer"
+ provides="zope.app.interfaces.container.IRemoveSource"
+ for="zope.app.interfaces.container.IContainer"
+ factory=".remove.RemoveSource"
/>
<event:subscribe
=== Zope3/src/zope/app/container/copypastemove.py 1.10 => 1.10.24.1 ===
--- Zope3/src/zope/app/container/copypastemove.py:1.10 Sun Jun 8 12:39:46 2003
+++ Zope3/src/zope/app/container/copypastemove.py Mon Sep 8 14:21:19 2003
@@ -24,13 +24,12 @@
from zope.app.interfaces.container import IContainerNamesContainer
from zope.app.interfaces.container import ICopySource, INoChildrenCopySource
from zope.app.interfaces.container import IMoveSource
-from zope.app.interfaces.container import IOptionalNamesContainer
from zope.app.interfaces.container import IPasteNamesChooser
from zope.app.interfaces.container import IPasteTarget
from zope.app.interfaces.content.folder import ICloneWithoutChildren
+from zope.app.location import locationCopy
from zope.component import getAdapter
from zope.interface import implements
-from zope.app.context import ContextWrapper
from zope.proxy import removeAllProxies
import copy
@@ -43,8 +42,7 @@
self.context = container
def acceptsObject(self, key, obj):
- '''Allow the container to say if it accepts the given wrapped
- object.
+ '''Allow the container to say if it accepts the given object.
Returns True if the object would be accepted as contents of
this container. Otherwise, returns False.
@@ -77,8 +75,7 @@
container = self.context
if not key:
- if not (IOptionalNamesContainer.isImplementedBy(container)
- or IContainerNamesContainer.isImplementedBy(container)):
+ if not IContainerNamesContainer.isImplementedBy(container):
raise ValueError("Empty names are not allowed")
# We remove the proxies from the object before adding it to
@@ -117,7 +114,6 @@
container = self.context
object = container[key]
- object = ContextWrapper(object, container, name=key)
# here, we dont call the before delete hook
del container[key]
@@ -140,11 +136,11 @@
copyingTo is the unicode path for where the copy is to.
'''
+
value = self.context.get(key, None)
if value is not None:
value = removeAllProxies(value)
- value = copy.deepcopy(value)
- return ContextWrapper(value, self.context, name=key)
+ return locationCopy(value)
class NoChildrenCopySource:
@@ -165,8 +161,7 @@
value = removeAllProxies(value)
if not ICloneWithoutChildren.isImplementedBy(value):
return None
- value = value.cloneWithoutChildren()
- return ContextWrapper(value, self.context, name=key)
+ return value.cloneWithoutChildren()
class PasteNamesChooser:
=== Zope3/src/zope/app/container/find.py 1.7 => 1.7.2.1 ===
--- Zope3/src/zope/app/container/find.py:1.7 Fri Sep 5 14:43:20 2003
+++ Zope3/src/zope/app/container/find.py Mon Sep 8 14:21:19 2003
@@ -19,8 +19,6 @@
from zope.app.interfaces.find import IFind, IIdFindFilter
from zope.app.interfaces.container import IReadContainer
from zope.interface import implements
-# XXX need to do this manually to wrap objects
-from zope.app.context import ContextWrapper
class FindAdapter(object):
@@ -38,7 +36,6 @@
result = []
container = self._context
for id, object in container.items():
- object = ContextWrapper(object, container, name=id)
_find_helper(id, object, container,
id_filters, object_filters,
result)
@@ -64,7 +61,6 @@
container = object
for id, object in container.items():
- object = ContextWrapper(object, container, name=id)
_find_helper(id, object, container, id_filters, object_filters, result)
class SimpleIdFindFilter(object):
=== Zope3/src/zope/app/container/ordered.py 1.5 => 1.5.10.1 ===
--- Zope3/src/zope/app/container/ordered.py:1.5 Fri Aug 1 15:56:49 2003
+++ Zope3/src/zope/app/container/ordered.py Mon Sep 8 14:21:19 2003
@@ -23,8 +23,9 @@
from persistence.dict import PersistentDict
from persistence.list import PersistentList
from types import StringTypes, TupleType, ListType
+from zope.app.container.contained import Contained, contained, uncontained
-class OrderedContainer(Persistent):
+class OrderedContainer(Persistent, Contained):
""" OrderedContainer maintains entries' order as added and moved.
>>> oc = OrderedContainer()
@@ -194,7 +195,8 @@
"ascii or unicode string" % key)
if len(key) == 0:
raise ValueError("The key cannot be an empty string")
- self._data[key] = object
+
+ self._data[key] = contained(object, self, key)
if not existed:
self._order.append(key)
@@ -221,6 +223,7 @@
1
"""
+ uncontained(self._data[key])
del self._data[key]
self._order.remove(key)
=== Zope3/src/zope/app/container/sample.py 1.7 => 1.7.24.1 ===
--- Zope3/src/zope/app/container/sample.py:1.7 Tue Jun 3 10:19:31 2003
+++ Zope3/src/zope/app/container/sample.py Mon Sep 8 14:21:19 2003
@@ -26,8 +26,9 @@
from zope.app.interfaces.container import IContainer
from zope.interface import implements
+from zope.app.container.contained import Contained, contained, uncontained
-class SampleContainer(object):
+class SampleContainer(Contained):
"""Sample container implementation suitable for testing.
It is not suitable, directly as a base class unless the subclass
@@ -97,9 +98,11 @@
"ascii or unicode string" % key)
if len(key) == 0:
raise ValueError("The key cannot be an empty string")
- self.__data[key] = object
+
+ self.__data[key] = contained(object, self, key)
return key
def __delitem__(self, key):
'''See interface IWriteContainer'''
+ uncontained(self.__data[key])
del self.__data[key]
=== Removed File Zope3/src/zope/app/container/zopecontainer.py ===
More information about the Zope3-Checkins
mailing list