- ccPublisher
- Zope 3
- smarter software
- dumber people
There was ccPublisher
![]()
and it was good.
"Yea, verily, I shalt take the code and make derivative works."
and it was a pain in the ass.
- Customization is hard
- People want features
- not necessarily hard to implement
- just not appropriate for the core
- uploading was easy...
- ...customization should be easy
- redesign of Zope 2
- implements a "component architecture"
- separates application server from support libraries
- Minimal externals -- zope.interface
- "Java-style" interfaces
- Customize it? Subclass it!
- and it was really crap
- 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
- Application functionality is broken into components
- Components communicate via events
- Which lets people be stupid
if field.persist:
event = p6.metadata.events.LoadMetadataEvent(
self.metagroup.appliesTo,
self.metagroup, field,
)
zope.component.handle(event)
zope.component.handle(
p6.metadata.events.UpdateMetadataEvent(
self.metagroup.appliesTo,
field,
widget.GetValue()
))
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.")
class LoadMetadataEvent(object):
zope.interface.implements(ILoadMetadataEvent)
def __init__(self, item, group, field):
...
- components encourage cohesive code
- but don't handle the extension use case
- and we still need to instantiate everything
- 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
we declare
- 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
<subscriber
for=".events.ILoadMetadataEvent"
handler=".adapters.loadMetadata"
/>
<field id="title"
label="Title of Work"
type="p6.metadata.types.ITextField"
validator="ccpublisher.validators.validateTitle"
canonical="http://purl.org/dc/elements/1.1/title"
/>
- 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
...
<preferences
id="blogping"
label="Blog Integration" >
<field id="xml_url"
type="str"
label="XML-RPC URL" />
<field id="username"
type="str"
label="Username" />
...
<subscriber
for="p6.storage.events.IStored"
handler=".blogping.AfterStored"
/>
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:
...
- used distutils, py2exe, py2app for earlier release
- unfortunately py2exe doesn't play well with ZCML
- solution:
- duplicate the ZCML
- patch the ZCML loader
- eggs
- use decorators instead of ZCML for some registrations
- oh yeah, actual derivatives
- 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
Questions?