.. footer :: PyCon 2006 - 25 February 2006 .. include:: ======================================== Building Extensible Desktop Applications ======================================== | Nathan R. Yergler | Software Engineer, | Creative Commons Agenda ------ .. class:: incremental * ccPublisher * Zope 3 * smarter software * dumber people In the beginning... ------------------- .. class:: incremental There was ccPublisher .. image:: images/ccpublisher.png and it was good. Seeing ccPublisher was all alone... ----------------------------------- .. class:: incremental .. class:: huge center "Yea, verily, I shalt take the code and make derivative works." .. image:: images/ourmedia.gif .. image:: images/jamloader_logo.png and it was a pain in the ass. Problems -------- .. class:: incremental * Customization is hard * People want features * not necessarily hard to implement * just not appropriate for the core What We Wanted to Solve ----------------------- * uploading was easy... * ...customization should be easy Zope 3 ------ * redesign of Zope 2 * implements a "component architecture" * separates application server from support libraries First Attempt ------------- .. class:: incremental * Minimal externals -- zope.interface * "Java-style" interfaces * Customize it? Subclass it! * and it was really crap Current Effort -------------- .. class:: incremental * Everything is a component * Some interfaces you conform to * Only subclass to get functionality "for free" * Using the Zope 3 component model and event dispatch Event & Component Model ----------------------- * Application functionality is broken into components * Components communicate via events * Which lets people be stupid For example... -------------- :: if field.persist: event = p6.metadata.events.LoadMetadataEvent( self.metagroup.appliesTo, self.metagroup, field, ) zope.component.handle(event) ...and another -------------- .. class:: incremental :: zope.component.handle( p6.metadata.events.UpdateMetadataEvent( self.metagroup.appliesTo, field, widget.GetValue() )) * We need to know how events work * but don't need to know what happens after they fire Events (1) ---------- :: class ILoadMetadataEvent(zope.interface.Interface): item = zope.interface.Attribute( "The item or interface the field applies to.") group = zope.interface.Attribute( "The metadata group this field belongs to.") field = zope.interface.Attribute( "The metadata field being updated.") value = zope.interface.Attribute( "The new value of the metadata field.") Events (2) ---------- :: class LoadMetadataEvent(object): zope.interface.implements(ILoadMetadataEvent) def __init__(self, item, group, field): ... Configuration ------------- .. class:: incremental * components encourage cohesive code * but don't handle the extension use case * **and** we still need to instantiate everything ZCML ---- .. class:: incremental * ZCML is a markup language * uses configuration directives to trigger actions * Zope 3 uses it for registering adapters, etc * we use it for that, along with some custom directives CC + ZCML --------- we declare .. class:: incremental * what backend(s) the application will use * what metadata fields we want to collect * how the user interface will be put together any extension can add to any of these areas Handler Registration -------------------- :: .. class:: incremental * registers a global handler * items which start with ``.`` are relative Metadata Fields --------------- :: Extensions ---------- .. class:: incremental * Configuration happens at run time * So we can add functionality at run time * Extensions use same model as core * Framework just knows where to look Extension Preferences --------------------- :: ... ... Extension Registration ---------------------- :: Extension Implementation ------------------------ :: def AfterStored(event): """Subscriber for WorkStored (IStored) events -- prompts the user to publish to their blog. """ result = wx.MessageDialog( None, "Blog this submission?", "Blogping", wx.YES_NO).ShowModal() if result == wx.ID_YES: ... Packaging --------- .. class:: incremental * used distutils, py2exe, py2app for earlier release * unfortunately py2exe doesn't play well with ZCML * solution: .. class:: incremental * duplicate the ZCML * patch the ZCML loader Future ------ .. class:: incremental * eggs * use decorators instead of ZCML for some registrations * oh yeah, actual derivatives Conclusion ---------- * Zope 3 components have allowed us * to clean up our own code * to create tasks that people can jump in and complete * to make derivative works easy, er, easier Thank you --------- .. class:: huge center Questions? http://yergler.net/yiki/PyCon2006