[z3-five] Does Five support Local Utilities?
Philipp von Weitershausen
philipp at weitershausen.de
Tue Sep 19 12:01:13 CEST 2006
Chris Withers wrote:
> There are true global utilities that require no configuration that
> implement IOutput, such as the default output renderer which takes the
> Twiddler DOM and turns it into a lump of text:
>
> from twiddler.interfaces import IOutput
> from *somewhere* import _render
> def Default(root,*args,**kw):
> output = []
> _render(output, root._root, {})
> return u''.join(output)
> directlyProvides(Default,IOutput)
>
> This is easy enough to expose through the following zcml:
>
> <utility provides="twiddler.interfaces.IOutput"
> component="twiddler.output.default.Default"
> name="Default"/>
I see.
> However, I was hoping to use something like utilities for objects that
> implement the same interface but which require configuration.
Right.
> For example, Twiddler has an output renderer that returns an
> email.MIMEMultiPart-ish object which also has a send method:
>
> class Email:
>
> implements(IOutput)
>
> def __init__(self,
> smtp_host='localhost',
> smtp_port='25',
> mfrom=None,
> mto=None,...etc...)
> # do stuff
> pass
>
>
> def __call__(self,root,*args,**kw):
> # gubbinz goes here
> return MTMultipart(self,
> values['mfrom'],
> values['mto'],
> **multipart_kw)
(Interlude:
Note that Zope 3 has a decent mail framework that's transaction aware
and all that, so while you might want to create the mail message
yourself, you probably want to use zope.sendmail [zope.app.mail
previously] for sending it out. Plus, it feels weird to do the mail
sending in an twiddler output renderer, but I don't know the framework...
)
> As you can see, this has configuration that is likely to be specific to
> the individual Twiddler: who the email is to, what smtp server to use,
> etc. Of course, you *might* want to share this between several twiddlers
> if, for example, you're sending several different mails but that all
> share the same From address and use the same smtp server.
>
> I currently have this registered using the following zcml:
>
> <utility provides="twiddler.interfaces.IOutput"
> factory="twiddler.output.emailer.Email"
> name="Emailer"/>
>
> ...which, given what you've told me previously, is why I have the
> deepcopy in the Twiddler.setInput pseudocode above. The logic is roughly
> "if the input/output/whatever if configurable, then copy it and store
> the copy, otherwise just store a reference to the global utility"...
>
> Is that evil?
At least storing the twiddler tree in the global utility seems weird to
me. I *think* you could express all this better through adapters. Let's
take the first example:
class DefaultRenderer(object):
adapts(ITwiddler)
implements(IOutput)
def __init__(self, context):
self.context = context
def __call__(self, *args, **kw):
root = self.context
return u''.join(_render(output, root._root, {}))
The mail rendering could be expressed with a different adapter:
class MailRenderer(DefaultRenderer):
adapts(IMailTwiddler)
smtp_host = 'localhost'
smtp_port = 25
mfrom = None
mto = None
def __call__(self, *args, **kw):
return MTMultipart(self,
values['mfrom'],
values['mto'],
**multipart_kw).to_string()
Now you would just register different incarnations of this mail renderer
(with different configuration values) for your various twiddlers. The
only downside is that you need marker interfaces to express this
properly. Or you use named adapters.
Philipp
More information about the z3-five
mailing list