[Zope3-dev] comments on Guido's diary

Steve Alexander steve@cat-box.net
Mon, 09 Dec 2002 16:22:52 +0000


Tres sent me the rest of Guido's diary email. I guess my mail client / 
mail server must have eaten it.

I'll comment on interesting issues, as before.

(on wrapped_self used as the first argument of ContextMethods)

> I'm willing to accept this and will try to get used
> to it.  I note that PyChecker may need to be educated about this
> convention.

Right. Is PyChecker being run automatically on Zope 3 sources at the moment?

 > He [Jim]
> proposed a compromise: allow an extra piece of data (a 'memento',
> Steve called it; I think this is a term from the Gang-of-Four patterns
> book)

That's right.

> to be given at subscription time that gets passed as a second
> argument to notify().  Steve may undertake this refactoring:
> 
>     class ISubscribable(Interface):
>         def subscribe(interface, memento=None): ...
> 
>     class ISubscriber(Interface):
>          def notify(event, memento=None): ...
> 
> For backwards compatibility (i.e.  to avoid having to add a memento
> argument to every notify() method in existence) I'd propose that the
> subscribable calls notify() as follows:
> 
>     if memento is None:
>         subscriber.notify(event)
>     else:
>         subscriber.notify(event, memento)

There aren't all that many notify() methods in existence.

If I refactor as above, then I think I'd make a new interface for 
IMementoSubscriber:

class ISubscriber(Interface):
     def notify(event):
         '''Notify me of an event'''

class IMementoSubscriber(ISubscriber):
     def notify(event, memento=None):
         '''Notify me of an event with a memento'''

Then, I'd do as Guido suggests.
I'll chat with the people at the Vilnius sprint about this refactoring. 
Other comments are also welcome.


> Then the above code could be refactored as follows:
> 
>         hub.subscribe(self, IObjectRegisteredHubEvent, 'index')
>         hub.subscribe(self, IObjectModifiedHubEvent, 'index')
>         hub.subscribe(self, IObjectUnregisteredHubEvent, 'unindex')
> 
>     def notify(self, event, memento):
>         if memento == 'index':
>             ...call index_doc...
>         else:
>             ...call unindex_doc...

How about a magical, but safe version?

     def subscribeToEvents(self, hub):
         hub.subscribe(self, IObjectRegisteredHubEvent, '_index')
         hub.subscribe(self, IObjectModifiedHubEvent, '_index')
         hub.subscribe(self, IObjectUnregisteredHubEvent, '_unindex')

     def _index(self, event):
         '''do indexing'''
         # ...

     def _unindex(self, event):
         '''do unindexing'''
         # ...

     def notify(self, event, memento=None):
         if memento in ('_index', '_unindex'):
             getattr(self, memento)(event)



>  I also believe I could do batching from ZPT using Python expressions,

Sure you can. And there's stuff in ZTUtils to help with that. I've tried 
it both ways, and making a view class for this is *much* nicer, easier 
to read, and easier to understand and maintain.

> Note that adding objects directly to the ZODB would be
> wrong, because that would bypass all the Zope/App machinery for
> events, locations, etc.

Right. However, if we use the correct API for adding things to 
containers, we can do that from the ZODB.

The steps are a bit like this:

   1: Traverse to the container you want to add objects to, by calling
      the 'traverse' convenience function from Zope.App.Traversing.

   2: Get an IZopeContainer adapter for your container.

   3: Add stuff to this adapter, using its 'setObject' method.

   4: Commit the transaction.

All appropriate events will be sent out.


There is no such adapter for a ZPT or a File object, though. So if you 
modify one of those objects, you'd have to do so through a view that 
sends the appropriate events out, or you'd have to send your own events 
out. These events will just be ObjectModifiedEvents though, so that's no 
great trouble.

[Steve has brief discussion with Jim about this]
I want to look into semi-automatically generating the appropriate 
adapters for these cases, perhaps from a simple piece of ZCML.

--
Steve Alexander