[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