[Zope-dev] CopySupport bug or feature?

2005-08-08 Thread Geoff Davis
I have been developing some classes that need to know when they are copied
or moved.  I have been achieving this by adding my own versions of
_notifyOfCopyTo, _postCopy, and manage_afterClone.  Everything works as
expected when you copy / paste an individual object.  However, I have
recently been made aware of a problem with this approach: if you copy not
the object itself, but rather a folder containing the object, only
manage_afterClone is called.  In looking through OFS/CopySupport.py and
OFS/ObjectManager.py, I discovered the source of the problem:
manage_afterClone is called recursively on ObjectManagers, but
_notifyOfCopyTo and _postCopy are not.

Is this intentional?  If not, I'd like to check in a fix.

Geoff



___
Zope-Dev maillist  -  Zope-Dev@zope.org
http://mail.zope.org/mailman/listinfo/zope-dev
**  No cross posts or HTML encoding!  **
(Related lists - 
 http://mail.zope.org/mailman/listinfo/zope-announce
 http://mail.zope.org/mailman/listinfo/zope )


Re: [Zope-dev] CopySupport bug or feature?

2005-08-08 Thread Bertrand Mathieu
There's a bug opened for a related problem
(http://www.zope.org/Collectors/Zope/1028) (pending since zope 2.6)
I feel that at least an API clarification is needed here.

Le lundi 08 août 2005 à 11:05 -0400, Geoff Davis a écrit :
 manage_afterClone is called.  In looking through OFS/CopySupport.py and
 OFS/ObjectManager.py, I discovered the source of the problem:
 manage_afterClone is called recursively on ObjectManagers, but
 _notifyOfCopyTo and _postCopy are not.
 
 Is this intentional?  If not, I'd like to check in a fix.

-- 
Bertrand Mathieu
Ingeniweb http://www.ingeniweb.com

___
Zope-Dev maillist  -  Zope-Dev@zope.org
http://mail.zope.org/mailman/listinfo/zope-dev
**  No cross posts or HTML encoding!  **
(Related lists - 
 http://mail.zope.org/mailman/listinfo/zope-announce
 http://mail.zope.org/mailman/listinfo/zope )


[Zope-dev] Re: CopySupport bug or feature?

2005-08-08 Thread Geoff Davis
I've been talking to people on #zope about this.  They're scared to
touch the methods for backward compatibility reasons.

Maybe the way to go is to create some new methods that are called
recursively on objects when they are copied or moved.  How about:

def _beforeMove(self, 
destination_container, 
destination_path,
recurse=True):
   # destination_container may be None (since for subobjects, the
   #destination will not have been created yet)
   # destination_path is a tuple containing the physical path of
   #the new container (which may not yet exist)
   # call subobjects recursively if recurse flag is True
   #
   # default implementation does nothing and returns self

def _afterMove(self, source_container, recurse=True)
   # source_container may be None (since for subobjects, the
   #source may have been moved elsewhere)
   # source_path is a tuple containing the physical path of 
   #the old container (which may no longer exist) 
   # call subobjects recursively if recurse flag is True 
   #
   # default implementation does nothing and returns self 

def _beforeCopy(self, destination_container, recurse=True):
   # destination_container may be None (since for subobjects, the
   #destination will not have been created yet)
   # destination_path is a tuple containing the physical path of
   #the new container (which may not yet exist)
   # call subobjects recursively if recurse flag is True
   #
   # default implementation does nothing and returns self
 
def _afterCopy(self, source_container, original_object, recurse=True):
   # source_path is a tuple containing the physical path of 
   #the new container (which should still exist) 
   # call subobjects recursively if recurse flag is True 
   #
   # default implementation does nothing and returns self

The calls would look something like:

ob = ob._beforeMove(destination, destination.getPhysicalPath(), True)
... 
moved_ob = moved_ob._afterMove(source, source.getPhysicalPath(), True)

etc


Once we have a decent event system in place, these methods could be the
place where copy / move events are generated.

Thoughts?

Geoff

On Mon, 08 Aug 2005 11:26:55 -0400, Chris McDonough wrote:

 I've been able to get around this by creating a _notifyOfCopyTo on the
 folder type that does the recursion.  There's a delicate dance in some
 of my code that does some work in _notifyOfCopyTo and other work in
 _getCopy.  This could be improved I bet, but touching the code means
 that you surely own it forever. ;-)
 
 On Mon, 2005-08-08 at 11:05 -0400, Geoff Davis wrote:
 I have been developing some classes that need to know when they are copied
 or moved.  I have been achieving this by adding my own versions of
 _notifyOfCopyTo, _postCopy, and manage_afterClone.  Everything works as
 expected when you copy / paste an individual object.  However, I have
 recently been made aware of a problem with this approach: if you copy not
 the object itself, but rather a folder containing the object, only
 manage_afterClone is called.  In looking through OFS/CopySupport.py and
 OFS/ObjectManager.py, I discovered the source of the problem:
 manage_afterClone is called recursively on ObjectManagers, but
 _notifyOfCopyTo and _postCopy are not.
 
 Is this intentional?  If not, I'd like to check in a fix.
 
 Geoff
 


___
Zope-Dev maillist  -  Zope-Dev@zope.org
http://mail.zope.org/mailman/listinfo/zope-dev
**  No cross posts or HTML encoding!  **
(Related lists - 
 http://mail.zope.org/mailman/listinfo/zope-announce
 http://mail.zope.org/mailman/listinfo/zope )


Re: [Zope-dev] Re: CopySupport bug or feature?

2005-08-08 Thread Sidnei da Silva
On Mon, Aug 08, 2005 at 12:36:30PM -0400, Geoff Davis wrote:
| I've been talking to people on #zope about this.  They're scared to
| touch the methods for backward compatibility reasons.
| 
| Maybe the way to go is to create some new methods that are called
| recursively on objects when they are copied or moved.  How about:

As long as you write tests and make sure webdav.Resource also calls
those methods on MOVE/COPY, I'm fine with it.


-- 
Sidnei da Silva
Enfold Systems, LLC.
http://enfoldsystems.com
___
Zope-Dev maillist  -  Zope-Dev@zope.org
http://mail.zope.org/mailman/listinfo/zope-dev
**  No cross posts or HTML encoding!  **
(Related lists - 
 http://mail.zope.org/mailman/listinfo/zope-announce
 http://mail.zope.org/mailman/listinfo/zope )


[Zope-dev] Re: CopySupport, hooks, events

2005-08-08 Thread Florent Guillaume

Geoff Davis wrote:

I've been talking to people on #zope about this.  They're scared to
touch the methods for backward compatibility reasons.

Maybe the way to go is to create some new methods that are called
recursively on objects when they are copied or moved.  How about:

def _beforeMove(self, 
		destination_container, 
		destination_path,

recurse=True):
   # destination_container may be None (since for subobjects, the
   #destination will not have been created yet)
   # destination_path is a tuple containing the physical path of
   #the new container (which may not yet exist)
   # call subobjects recursively if recurse flag is True
   #
   # default implementation does nothing and returns self

def _afterMove(self, source_container, recurse=True)
   # source_container may be None (since for subobjects, the
   #source may have been moved elsewhere)
   # source_path is a tuple containing the physical path of 
   #the old container (which may no longer exist) 
   # call subobjects recursively if recurse flag is True 
   #
   # default implementation does nothing and returns self 


def _beforeCopy(self, destination_container, recurse=True):
   # destination_container may be None (since for subobjects, the
   #destination will not have been created yet)
   # destination_path is a tuple containing the physical path of
   #the new container (which may not yet exist)
   # call subobjects recursively if recurse flag is True
   #
   # default implementation does nothing and returns self
 
def _afterCopy(self, source_container, original_object, recurse=True):
   # source_path is a tuple containing the physical path of 
   #the new container (which should still exist) 
   # call subobjects recursively if recurse flag is True 
   #

   # default implementation does nothing and returns self

The calls would look something like:

ob = ob._beforeMove(destination, destination.getPhysicalPath(), True)
... 
moved_ob = moved_ob._afterMove(source, source.getPhysicalPath(), True)


etc


Once we have a decent event system in place, these methods could be the
place where copy / move events are generated.

Thoughts?


I'd prefer names less potentially prone to clashes with existing code, 
namely _beforeItemMove, _afterItemCopy, etc.


Also I tried to make a point on IRC about the recursion, and how we can 
switch this model to an event system later, but I probably wasn't clear 
enough. I'll try to explain better, but please bear with me :)



First and foremost, I want to be able to switch from the current system 
where each class has to implement (or inherit) _beforeItemMove so that 
recursion applies, which would conceptually mean a base class or a mixin, to 
a system driven by events.


Very importantly, this means that it's not _beforeItemMove's job to do the 
recursion. Why? Because suppose I inherit from a base class that has 
something to do before the move, and I want to add behavior to that. I'll 
have to call the base class, let it do its recursion, and then do my 
behavior on the current object. But suppose I inherit from two base classes 
that both had a _beforeItemMove that did recursion ? Then the recursion has 
to be defined and done only once, or you'd have double recursions (which 
turns into an exponential complexity). Maybe in some kind of unique base 
class? That's a total mess, I don't want to have to add artificial base 
classes to my code when there's no need to. I want the recursing behavior to 
be defined in a component (à la Zope 3), not in a base class. So the first 
consequence of having a clean approach is that:


It's not the hook's job to do the recursion.

So the recursion has to be done by external code, a component, that calls 
all the relevant objects.



Now, in the current Zope 2 system having a class with a manage_beforeDelete 
(for instance) that just does pass means that the recursion is stopped. We 
want to keep that flexibility; this is easily done by having the hook return 
True if it wants to recurse (or to stop recursion -- we have to find what's 
best).



Here's how an event system would work (using afterItemCopy as an example):

1. something decides to copy an object. A beforeCopy event is sent. Then 
the copy is done. The an afterCopy event is sent.


2. some code having the need to tidy up things after the copy has a 
subscriber subscribed to the afterCopy event. For instance, there could be 
a subscriber in CMFCatalogAware.py that indexes the new objects, calling 
indexObject on each. A subscriber implements a policy, in this case it would 
be copied objects have to be indexed in their new place. Notice, it's not 
indexObject's role to do any recursion.


3. the subscriber may or may not want the recursion to apply. How it does 
that is up to its implementation.


I'm stressing point 3 here because if I copy 100.000 objects I don't want 
the default system to send 100.000 events. If I have an efficient way of 
doing my 

[Zope-dev] Re: CopySupport, hooks, events

2005-08-08 Thread Geoff Davis
Florent, thanks for a thoughtful reply.

Maybe we should start the larger discussion in moving to an event-driven
OFS in Zope 2.8/2.9 using Five? Does Five support Z3's events (does Z3
have events yet? I have ordered Phillip's Z3 book but it has yet to arrive...)

I'm cross posting to the Plone folks to see what they think.

Geoff


On Mon, 08 Aug 2005 20:29:38 +0200, Florent Guillaume wrote:
 
 I'd prefer names less potentially prone to clashes with existing code, 
 namely _beforeItemMove, _afterItemCopy, etc.
 
 Also I tried to make a point on IRC about the recursion, and how we can 
 switch this model to an event system later, but I probably wasn't clear 
 enough. I'll try to explain better, but please bear with me :)
 
 
 First and foremost, I want to be able to switch from the current system 
 where each class has to implement (or inherit) _beforeItemMove so that 
 recursion applies, which would conceptually mean a base class or a mixin, to 
 a system driven by events.
 
 Very importantly, this means that it's not _beforeItemMove's job to do the 
 recursion. Why? Because suppose I inherit from a base class that has 
 something to do before the move, and I want to add behavior to that. I'll 
 have to call the base class, let it do its recursion, and then do my 
 behavior on the current object. But suppose I inherit from two base classes 
 that both had a _beforeItemMove that did recursion ? Then the recursion has 
 to be defined and done only once, or you'd have double recursions (which 
 turns into an exponential complexity). Maybe in some kind of unique base 
 class? That's a total mess, I don't want to have to add artificial base 
 classes to my code when there's no need to. I want the recursing behavior to 
 be defined in a component (à la Zope 3), not in a base class. So the first 
 consequence of having a clean approach is that:
 
  It's not the hook's job to do the recursion.
 
 So the recursion has to be done by external code, a component, that calls 
 all the relevant objects.
 
 
 Now, in the current Zope 2 system having a class with a manage_beforeDelete 
 (for instance) that just does pass means that the recursion is stopped. We 
 want to keep that flexibility; this is easily done by having the hook return 
 True if it wants to recurse (or to stop recursion -- we have to find what's 
 best).
 
 
 Here's how an event system would work (using afterItemCopy as an example):
 
 1. something decides to copy an object. A beforeCopy event is sent. Then 
 the copy is done. The an afterCopy event is sent.
 
 2. some code having the need to tidy up things after the copy has a 
 subscriber subscribed to the afterCopy event. For instance, there could be 
 a subscriber in CMFCatalogAware.py that indexes the new objects, calling 
 indexObject on each. A subscriber implements a policy, in this case it would 
 be copied objects have to be indexed in their new place. Notice, it's not 
 indexObject's role to do any recursion.
 
 3. the subscriber may or may not want the recursion to apply. How it does 
 that is up to its implementation.
 
 I'm stressing point 3 here because if I copy 100.000 objects I don't want 
 the default system to send 100.000 events. If I have an efficient way of 
 doing my bookkeeping, I don't want the event system do screw things up 
 behind my back. Note for instance that in CMF reindexObjectSecurity does not 
 do recursion like manage_afterAdd does, because it has optimized ways to do 
 its job without recursing using objectValues().
 
 So I strongly believe the default event system should send a simple event on 
 copy (and I think I'll have to fight to get my way in Zope 3...). Now, if 
 something wants to recurse, it's free to do so, and maybe send more events. 
 But I want the system to be able to work without that.
 
 Using this system, there could be a default subscriber in OFS/CopySupport.py 
 that calls _afterItemCopy on the toplevel object and then does the 
 recursion. The *subscriber* does the recursion, not _afterItemCopy.
 
 But we're not there yet (no events in Zope 2), so instead of sending an 
 event that's caught by a subscriber that does a recursion, this can be done 
 for now by calling directly the code equivalent to the subscriber. Later 
 we'll move to the event system. (And it is my hope that we can deprecate 
 manage_beforeDelete  al. too.)
 
 
 So I propose:
 
 def _beforeItemMove(dest_container, dest_path):
  
  Called before an item is moved.
 
  dest_container may be None (since for subobjects, the
  destination will not have been created yet).
 
  dest_path is a tuple containing the physical path of
  the new container (which may not yet exist).
 
  Returns True if recursion should stop.
  
 
 def _afterItemMove(source_container, source_path):
  
  Called afer an item has been moved.
 
  source_container may be None (since for subobjects, the
  source may have been moved elsewhere).
 
  source_path 

Re: [Zope-dev] Re: CopySupport, hooks, events

2005-08-08 Thread Sidnei da Silva
On Mon, Aug 08, 2005 at 03:16:18PM -0400, Geoff Davis wrote:
| Florent, thanks for a thoughtful reply.
| 
| Maybe we should start the larger discussion in moving to an event-driven
| OFS in Zope 2.8/2.9 using Five? Does Five support Z3's events

Yes. Actually, nothing special is required to support Z3 events except
loading the meta.zcml files that makes the subscriber directive
available, and Five does that.

| (does Z3
| have events yet? I have ordered Phillip's Z3 book but it has yet to arrive...)

'Course it does.

-- 
Sidnei da Silva
Enfold Systems, LLC.
http://enfoldsystems.com
___
Zope-Dev maillist  -  Zope-Dev@zope.org
http://mail.zope.org/mailman/listinfo/zope-dev
**  No cross posts or HTML encoding!  **
(Related lists - 
 http://mail.zope.org/mailman/listinfo/zope-announce
 http://mail.zope.org/mailman/listinfo/zope )