[PEAK] peak.web in October

Phillip J. Eby pje at telecommunity.com
Fri Oct 22 22:54:51 EDT 2004


At 11:12 AM 10/5/04 -0400, Phillip J. Eby wrote:
>As some of you may have noticed from last week's flurry of checkins, I'm 
>finally doing the peak.web refactoring I've been talking about off and on 
>for the last several months.  At this point, the plan is to complete at 
>least these peak.web "Tier 1" features this month:
>
>[snip]
>  * Overhaul PWT to use the new this:/content: attribute mechanism 
> (Started; the needed XML parser is in a draft status)
>
>  * Design and implement an XML dialect for site configuration, similar in 
> functionality to Zope 3's ZCML, but with the capability of structuring a 
> site or application's URL layout and "local" as well as "global" 
> configuration.  (Not started, but will use the same draft XML parser)
>
>  * Create view registration mechanisms for both .ini files and .xml files

A quick status update...  the main PWT overhaul is complete, but there are 
numerous features still to be added.  Specifically, most of the ones from 
my "PWT: layout, macros, parameters, etc." post on Tuesday.  However, as of 
today, I've implemented the '/params' mechanism, the ability to invoke a 
DOMlet from within another template, and the single vs. multi-value 
parameter checking.  I've also done some refactoring to support adding the 
various page-level options (page-layout, fragment-layout, content-type, etc.

The XML sitemap dialect is now basically complete.  I ended up changing 
some of the attribute names around, and/or made slight changes to how they 
worked.  For example, to include one sitemap in another, you use a 
'<location>' with an 'extends' attribute, that's a relative URL to the 
sitemap you want to include.  Anyway, there are a number of quirks and 
limitations with respect to inclusion, that I still need to sort out.  For 
the most part, you can't really override anything except the class of the 
location when you reuse a site map; you're pretty much limited to additions 
for the moment.  Still, this works for simple reuse of sitemap 
segments.  Also, I decided to forego the 'interfaces' attribute of the 
'<allow>' element, as I couldn't settle on final semantics for it, and it's 
just a convenient way to specify multiple attributes anyway, so you can 
just list individual attributes for now.  Finally, there is no easy way to 
define views or pages on a location.

Apart from these missing features and limitations/quirks, peak.web is now 
basically in its new shape, from a functional perspective.  However, it 
still has plenty of internal refactoring to go, as those missing features 
are added and the quirks taken out.  In fact, the main reason the features 
aren't there, and the quirks are, is because this is the best I could do 
without the needed refactorings.  However, with the bulk of the 
functionality in place, I can now do those refactorings backed up by a 
broad array of tests.

Including functional tests, which may be quite informative if you want a 
glimpse at what the future of peak.web looks like.  For example, here's a 
segment from one of the test sitemaps:

<location id="root" config="configure-test.ini">

     <container object="{'123':123, 'abc':'abc', 'both':[123,'abc']}"/>

     <content type="object">
         <import module="peak.web.templates" as="pwt"/>
         <view name="repr" expr="`ob`"/>
         <view name="test-params"
               expr="pwt.Replace(dataSpec=web.TraversalPath('/params/foo'))" />
         <view name="index_html" resource="peak.web.tests/showobject"/>
     </content>

     <content type="int" location="repr at root" />

     <content type="str" location="value at root">
         <view name="value" expr="ob"/>
     </content>

     <content type="list">
         <view name="index_html" resource="peak.web.tests/showlist"/>
     </content>

</location>

The above is a simple site with only three working URLS: '123', 'abc', and 
'both'.  All objects have a 'repr' view that returns the repr() of the 
object.  Integers' absolute URL is computed using their repr, while 
strings' absolute location is computed using their value.  Two simple PWT 
templates are used to render the default view (index_html) of objects in 
general, and lists in particular.

If you want to see what this looks like in your browser, you can do the 
following with a current CVS checkout of PEAK:

    peak launch ref:sitemap at pkgfile:peak.web.tests/test-sitemap.xml

Or you can run it under CGI/FastCGI/etc. by replacing 'launch' with the 
appropriate alternative command.  The same will be true for any sitemap 
files you create for your own applications.  Essentially, you'll prepend 
'ref:sitemap@' to a URL that points to your XML sitemap file.  Anyway, if 
you're running the 'test-sitemap', keep in mind that its root application 
URL has no default view, so you'll have to add '123', 'abc', or 'both' onto 
the end of the URL that comes up in your browser, in order to see the test 
output.

Anyway, if you're creating your own sitemap, you can use the 'class' 
attribute of 'location' tags to specify the class you'd like to use for a 
given location.  It should subclass 'web.Location', or at least implement 
'web.IConfigurableLocation'.  You can use a 'config' attribute to load an 
.ini file into the location once it's created.  The attribute can give 
either an absolute URL, or one that's relative to the sitemap's URL.

The really awesome thing about this, now that I'm actually seeing it work, 
is that it's looking like you can really create quite an elaborate 
application, using only the templates, a sitemap, and a little bit of 
Python glue to marry the UI to whatever your "domain model" is.  And the 
parts that make up that application are all resuable, skinnable, etc., to 
make new apps.  Indeed, I'm thinking that I could possibly make a simple 
documentation tool, along the lines of 'pydoc'/'peak help', using hardly 
anything but templates and a sitemap to configure the views.

In theory, it should be just as easy in Zope X3 to do these things, but in 
practice I don't know if that's really the case, since as far as I know 
ZCML doesn't let you really create a site map.  I believe you have to do 
that part actually in ZODB, not the file system.  But maybe somebody who's 
worked with Zope X3 more recently than I (Ulrich, perhaps?) can comment on 
that.

Certainly, peak.web's support for "Specialists" is going to be 
better.  Basically, to create a specialist, you just do something like:

     <location name="Customers" id="myapp.customers">

        <import module="myapp.storage" as="stg" />
        <import module="myapp.model" as="mdl" />

        <container object="stg.CustomerDM()" />

        <content type="mdl.Customer" location="cust_id at myapp.customers">
            <view name="...etc...
        </content>

     </location>

And voila, there's your specialist.  Well, it's missing any class-level 
methods, but it's basically there.  The above creates a location called 
'Customers' inside the current location of the sitemap, and registers it 
with a "location id" of 'myapp.customers', so that it can be found by any 
component that needs to refer to its location.  The location uses a 
'CustomerDM' as one of its containers, so going to 'Customers/foo' will 
attempt to look up 'foo' in the DM.

And when it finds a Customer object, then views defined in the 'content' 
section will apply.  (Normally, you'll define these content views at the 
application's top level, or in an .ini file, rather than restricting them 
to object under a particular location, but this is just an illustration.)

The 'location="cust_id at myapp.customers"' attribute says, "if you need the 
URL of a mdl.Customer object, take its 'cust_id' and append it to the URL 
of the location whose ID is 'myapp.customers'".  In this case, that 
location is the 'Customers' location, so if you have a Customer with a 
'cust_id' of 'foo', then its canonical URL will be 'Customers/foo' 
(preceded, of course, by whatever's the canonical URL of the parent 
component of the 'Customers' location).  Thus, whenever a template needs to 
generate a link to a customer object, it can use something like:

     <...this:url.href="." content:replace="fullname">Customer's full name 
will go here</a>

And a link to e.g. '../../Customers/foo' might be generated, depending on 
the current URL, and assuming that the template's current target object is 
a mdl.Customer at this point in the template.  Notice, by the way, that 
peak.web generates relative URLs for links whenever possible, in order to 
make it easier to generate "static file" sites that can be browsed 
regardless of their current physical URL (in e.g. the filesystem).

Anyway, things are looking pretty spiffy, but I expect I'll be spending a 
good bit of time to get this functional tier wrapped up by Halloween, as 
there are still many quirks to remove and a lot of PWT features yet to be 
added.




More information about the PEAK mailing list