<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Zope3 on Random notes from mg</title>
    <link>https://mg.pov.lt/blog/tags/zope3.html</link>
    <description>Recent content in Zope3 on Random notes from mg</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>en-us</language>
    <managingEditor>marius@gedmin.as (Marius Gedminas)</managingEditor>
    <webMaster>marius@gedmin.as (Marius Gedminas)</webMaster>
    <copyright>Copyright © 2004–2020 Marius Gedminas</copyright>
    <lastBuildDate>Sun, 04 Apr 2010 22:30:12 +0300</lastBuildDate>
    <atom:link href="https://mg.pov.lt/blog/tags/zope3/index.xml" rel="self" type="application/rss+xml" />
    
    <item>
      <title>Review: Grok 1.0 Web Development</title>
      <link>https://mg.pov.lt/blog/grok-book-review.html</link>
      <pubDate>Sun, 04 Apr 2010 22:30:12 +0300</pubDate>
      <author>marius@gedmin.as (Marius Gedminas)</author>
      <guid>https://mg.pov.lt/blog/grok-book-review.html</guid>
      <description>
&lt;p&gt;Disclaimer: I received a free review copy of this book. The book links are
affiliate links; I get a small amount from any purchase you make through them.&lt;/p&gt;

&lt;p&gt;&lt;a href=&#34;http://grok.zope.org/&#34;&gt;Grok&lt;/a&gt; is a Python web framework, built on
top of the Zope Toolkit, which is the core of what used to be called Zope 3 and
is now rebranded as BlueBream.  Confused yet?  Get used to it: the small
pluggable components are the heart and soul of ZTK, and the source of its
flexibility. It&#39;s not surprising that people take the same approach on a larger
scale: take Zope 3 apart into smaller packages and reassemble them into
different frameworks such as Grok, BlueBream or repoze.bfg.&lt;/p&gt;

&lt;p style=&#34;float: right; margin: 0 0 1em 1em&#34;&gt;
&lt;a href=&#34;http://www.packtpub.com/grok-1-0-web-development/book/mid/150310wgpfxa?utm_source=mg.pov.lt&amp;utm_medium=affiliate&amp;utm_content=blog&amp;utm_campaign=mdb_002715&#34;&gt;
  &lt;img src=&#34;https://mg.pov.lt/grok-book.jpg&#34;
       width=&#34;250&#34; height=&#34;309&#34; alt=&#34;Grok 1.0 Web Development by Carlos de la Guardia&#34; /&gt;
&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;The &lt;a
  href=&#34;http://www.packtpub.com/grok-1-0-web-development/book/mid/150310wgpfxa?utm_source=mg.pov.lt&amp;utm_medium=affiliate&amp;utm_content=blog&amp;utm_campaign=mdb_002715&#34;&gt;Grok
  book by Carlos de la Guardia&lt;/a&gt; introduces the framework by demonstrating
how to create a small but realistic To-do list manager.  I like this technique,
and it works pretty well.  The author covers many topics:&lt;/p&gt; 
&lt;ul&gt;
  &lt;li&gt; creation of a new project &lt;/li&gt;
  &lt;li&gt; simple views with Zope Page Templates &lt;/li&gt;
  &lt;li&gt; automatic form generation from schemas (with tweaks) &lt;/li&gt;
  &lt;li&gt; catalogs and indexes (my favourite chapter) &lt;/li&gt;
  &lt;li&gt; security: users, roles, permissions; authentication and authorization &lt;/li&gt;
  &lt;li&gt; extremely pluggable page layouts with viewlets and pagelets &lt;/li&gt;
  &lt;li&gt; basic ZODB, blobs, ZEO, database packing, backups with repozo &lt;/li&gt;
  &lt;li&gt; SQL databases, integration with SQLAlchemy (including a common
       transactional model) &lt;/li&gt;
  &lt;li&gt; component architecture: adapters and utilities &lt;/li&gt;
  &lt;li&gt; Martian: extending Grok by defining custom component directives &lt;/li&gt;
  &lt;li&gt; very short intro to testing (zope.testing, unit tests and doctests,
       functional tests with zope.testbrowsing) and debugging (pdb; AJAXy
       debugger, which looks exactly like the Pylons one with an uglier skin) &lt;/li&gt;
  &lt;li&gt; deployment (my second favourite chapter): paster, apache and mod_proxy,
       mod_wsgi, pound, squid, varnish, scalable deployments. &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Some important topics like internationalization, time zones, testing with
Selenium, and (especially) database migration (which is pretty specific for
ZODB) were not covered.&lt;/p&gt;

&lt;p&gt; &lt;strong&gt;If you want to learn about Grok, this book will be useful&lt;/strong&gt;,
but there&#39;s a caveat: there&#39;s the usual slew of typographical mistakes and
other errors I&#39;ve come to expect from books published by Packt.  It&#39;s their
third book I&#39;ve seen; all three had surprisingly high numbers of errors.  Some
had more, others had fewer.  The Grok book was on the high side and the first
one where I was tempted to record a &#34;&lt;a
  href=&#34;http://www.osnews.com/story/19266/WTFs_m&#34;&gt;WTFs per page&lt;/a&gt;&#34; metric.
The mistakes are easy to notice and correct, so they didn&#39;t impede my
understanding of the book&#39;s content.  Disclaimer: I&#39;ve been working with
Zope 3 for the last six-or-so years, so I was pretty familiar with the
underlying technologies, just not the thin Grok convenience layer. &lt;strong&gt;If
  minor errors annoy you, stay away.&lt;/strong&gt;  I haven&#39;t noticed any major
factual errors, although there were what I would consider some pretty important
omissions:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;ZODB is not as transparent as people tell you.  There are many gotchas,
  especially if you want to refactor your code without throwing away old
  databases.&lt;/li&gt;
  &lt;li&gt;&lt;tt&gt;bin/buildout&lt;/tt&gt; is free to recursively remove anything under
  &lt;tt&gt;parts&lt;/tt&gt;.  Keeping your database there is fine only if you don&#39;t mind
  occasionally starting from scratch.&lt;/li&gt;
  &lt;li&gt;&lt;tt&gt;repozo&lt;/tt&gt; does not back up blobs.&lt;/li&gt;
  &lt;li&gt;The ZODB transaction conflict resolution depends on being able to
  repeat requests several times; this is important if your code has external
  side effects (e.g. sends emails, creates files, pings 3rd party websites over
  HTTP).  Packages like megrok.rdb or zope.sendmail take care of this; it&#39;d be
  nice to be shown how to do that  for your own code before you discover this
  issue the hard way when your app starts charging people&#39;s credit cards three
  times every now and then. &lt;/li&gt;
  &lt;li&gt;You need to make sure you send out object events at appropriate times, or
  your catalog indexes won&#39;t be updated.&lt;/li&gt;
  &lt;li&gt;Permission and role grants are persistent: if you delete a user and then
  create a new one with the same username, the new user will have all the roles
  and permissions granted to the old one.  If you implement user deletion, you
  need to explicitly remove old grants.&lt;/li&gt;
  &lt;li&gt;The Zope security model expects every object to have a valid &lt;code&gt;__parent__&lt;/code&gt;
  attribute; permission/role grants will not work properly on objects without a
  &lt;code&gt;__parent__&lt;/code&gt;.  Most of the time this is taken care of
  automatically, but when it&#39;s not, you can get really confusing errors.&lt;/li&gt;
  &lt;li&gt;&lt;code&gt;applySkin&lt;/code&gt; should only be used for browser requests; blindly
  calling it from a traversal event handler can break WebDAV/XML-RPC.
  (Incidentally, I should file a bug about that; it should abort if you pass a
  non-browser request instead of silently converting it into a browser
  request.)&lt;/li&gt;
  &lt;li&gt;Allowing end-users to specify &lt;code&gt;++skin++&lt;/code&gt; in the URL can be a
  security hole.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Overall, Grok is pretty nice, especially compared to vanilla Zope 3.
However, when compared to frameworks like Pylons or Django, Grok appears more
complex and seemingly requires you to do additional work for unclear gain.  For
example, chapter 8 has you writing three components for every new form you add:
one for the form itself, one for a pagelet wrapping the form, and one for a
page containing the pagelet.  Most of that code is very similar with only the
names being different.  I&#39;m sure there are situations where this kind of
extreme componentization pays off (e.g. it lets you override particular bits on
particular pages to satisfy a particular client&#39;s requests, without affecting
any other clients), but the book doesn&#39;t convincingly demonstrate those
advantages.  Again, I may be biased here since I&#39;ve been enjoying those
advantages for the past six years, without ever having felt the pain of doing
similar customizations with a less flexible framework.  (It&#39;s a gap in my
professional experience that I&#39;m itching to fill.) &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Update:&lt;/strong&gt; &lt;a
  href=&#34;http://lateral.netmanagers.com.ar/weblog/posts/BB885.html&#34;&gt;some&lt;/a&gt; &lt;a
  href=&#34;http://blog.pythonisito.com/2010/03/review-grok-10-web-development.html&#34;&gt;other&lt;/a&gt;
&lt;a
  href=&#34;http://www.jmcneil.net/2010/03/review-grok-1-0-web-development/&#34;&gt;reviews&lt;/a&gt;
on Planet Python.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Update 2:&lt;/strong&gt; &lt;a
  href=&#34;http://blog.lowkster.com/2010/04/review-of-grok-web-development-10-part.html&#34;&gt;Another
  review&lt;/a&gt; (well, part 1 of one, but I got tired waiting for part 2).
&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Displaying multiline text in Zope 3</title>
      <link>https://mg.pov.lt/blog/zope3-displaying-multiline-text.html</link>
      <pubDate>Tue, 01 Dec 2009 20:52:03 +0200</pubDate>
      <author>marius@gedmin.as (Marius Gedminas)</author>
      <guid>https://mg.pov.lt/blog/zope3-displaying-multiline-text.html</guid>
      <description>
&lt;p&gt;zope.schema has Text and TextLine.  The former is for multiline text, the
latter is for a single line, as the name suggests.  Zope 3 forms will use a
text area for Text fields and an input box for TextLine fields.  Display
widgets, however, apply no special formatting (other than HTML-quoting of
characters like &amp;lt;, &amp;gt; and &amp;amp;), and since newlines are treated the same
way as spaces in HTML, your multiline text gets collapsed into a single
paragraph.&lt;/p&gt;

&lt;p&gt;Here&#39;s a pattern I&#39;ve been using in Zope 3 to display multiline user-entered
text as several paragraphs:&lt;/p&gt;

&lt;blockquote&gt;
&lt;pre&gt;
&lt;span class=&#34;keyword&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;name&#34;&gt;cgi&lt;/span&gt;

&lt;span class=&#34;keyword&#34;&gt;from&lt;/span&gt; &lt;span class=&#34;name&#34;&gt;zope&lt;/span&gt;.&lt;span class=&#34;name&#34;&gt;component&lt;/span&gt; &lt;span class=&#34;keyword&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;name&#34;&gt;adapts&lt;/span&gt;
&lt;span class=&#34;keyword&#34;&gt;from&lt;/span&gt; &lt;span class=&#34;name&#34;&gt;zope&lt;/span&gt;.&lt;span class=&#34;name&#34;&gt;publisher&lt;/span&gt;.&lt;span class=&#34;name&#34;&gt;browser&lt;/span&gt; &lt;span class=&#34;keyword&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;name&#34;&gt;BrowserView&lt;/span&gt;
&lt;span class=&#34;keyword&#34;&gt;from&lt;/span&gt; &lt;span class=&#34;name&#34;&gt;zope&lt;/span&gt;.&lt;span class=&#34;name&#34;&gt;publisher&lt;/span&gt;.&lt;span class=&#34;name&#34;&gt;interfaces&lt;/span&gt; &lt;span class=&#34;keyword&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;name&#34;&gt;IRequest&lt;/span&gt;


&lt;span class=&#34;def&#34;&gt;class&lt;/span&gt; &lt;span class=&#34;name&#34;&gt;SplitToParagraphsView&lt;/span&gt;(&lt;span class=&#34;name&#34;&gt;BrowserView&lt;/span&gt;):
    &lt;span class=&#34;string&#34;&gt;&#34;&#34;&#34;Splits a string into paragraphs via newlines.&#34;&#34;&#34;&lt;/span&gt;

    &lt;span class=&#34;name&#34;&gt;adapts&lt;/span&gt;(&lt;span class=&#34;name&#34;&gt;None&lt;/span&gt;, &lt;span class=&#34;name&#34;&gt;IRequest&lt;/span&gt;)

    &lt;span class=&#34;def&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;name&#34;&gt;paragraphs&lt;/span&gt;(&lt;span class=&#34;name&#34;&gt;self&lt;/span&gt;):
        &lt;span class=&#34;keyword&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;name&#34;&gt;self&lt;/span&gt;.&lt;span class=&#34;name&#34;&gt;context&lt;/span&gt; &lt;span class=&#34;keyword&#34;&gt;is&lt;/span&gt; &lt;span class=&#34;name&#34;&gt;None&lt;/span&gt;:
            &lt;span class=&#34;keyword&#34;&gt;return&lt;/span&gt; []
        &lt;span class=&#34;keyword&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;name&#34;&gt;filter&lt;/span&gt;(&lt;span class=&#34;name&#34;&gt;None&lt;/span&gt;, [&lt;span class=&#34;name&#34;&gt;s&lt;/span&gt;.&lt;span class=&#34;name&#34;&gt;strip&lt;/span&gt;() &lt;span class=&#34;keyword&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;name&#34;&gt;s&lt;/span&gt; &lt;span class=&#34;keyword&#34;&gt;in&lt;/span&gt; &lt;span class=&#34;name&#34;&gt;self&lt;/span&gt;.&lt;span class=&#34;name&#34;&gt;context&lt;/span&gt;.&lt;span class=&#34;name&#34;&gt;splitlines&lt;/span&gt;()])

    &lt;span class=&#34;def&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;name&#34;&gt;__call__&lt;/span&gt;(&lt;span class=&#34;name&#34;&gt;self&lt;/span&gt;):
        &lt;span class=&#34;keyword&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;string&#34;&gt;&#34;&#34;&lt;/span&gt;.&lt;span class=&#34;name&#34;&gt;join&lt;/span&gt;(&lt;span class=&#34;string&#34;&gt;&#39;&amp;lt;p&amp;gt;%s&amp;lt;/p&amp;gt;&lt;span class=&#34;escape&#34;&gt;\n&lt;/span&gt;&#39;&lt;/span&gt; % &lt;span class=&#34;name&#34;&gt;cgi&lt;/span&gt;.&lt;span class=&#34;name&#34;&gt;escape&lt;/span&gt;(&lt;span class=&#34;name&#34;&gt;p&lt;/span&gt;)
                        &lt;span class=&#34;keyword&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;name&#34;&gt;p&lt;/span&gt; &lt;span class=&#34;keyword&#34;&gt;in&lt;/span&gt; &lt;span class=&#34;name&#34;&gt;self&lt;/span&gt;.&lt;span class=&#34;name&#34;&gt;paragraphs&lt;/span&gt;())
&lt;/pre&gt;
&lt;/blockquote&gt;

&lt;p&gt;View registration&lt;/p&gt;

&lt;blockquote&gt;
&lt;pre&gt;
&amp;lt;&lt;span class=&#34;def&#34;&gt;configure&lt;/span&gt;
    xmlns=&#34;http://namespaces.zope.org/zope&#34;&amp;gt;

  &amp;lt;&lt;span class=&#34;def&#34;&gt;view&lt;/span&gt;
      &lt;span class=&#34;name&#34;&gt;for&lt;/span&gt;=&lt;span class=&#34;string&#34;&gt;&#34;*&#34;&lt;/span&gt;
      &lt;span class=&#34;name&#34;&gt;name&lt;/span&gt;=&lt;span class=&#34;string&#34;&gt;&#34;paragraphs&#34;&lt;/span&gt;
      &lt;span class=&#34;name&#34;&gt;type&lt;/span&gt;=&lt;span class=&#34;string&#34;&gt;&#34;zope.publisher.interfaces.browser.IBrowserRequest&#34;&lt;/span&gt;
      &lt;span class=&#34;name&#34;&gt;factory&lt;/span&gt;=&lt;span class=&#34;string&#34;&gt;&#34;.views.SplitToParagraphsView&#34;&lt;/span&gt;
      &lt;span class=&#34;name&#34;&gt;permission&lt;/span&gt;=&lt;span class=&#34;string&#34;&gt;&#34;zope.Public&#34;&lt;/span&gt;
      /&amp;gt;

&amp;lt;/&lt;span class=&#34;def&#34;&gt;configure&lt;/span&gt;&amp;gt;
&lt;/pre&gt;
&lt;/blockquote&gt;

&lt;p&gt;and usage&lt;/p&gt;

&lt;blockquote&gt;
&lt;pre&gt;
&amp;lt;&lt;span class=&#34;def&#34;&gt;p&lt;/span&gt; &lt;span class=&#34;name&#34;&gt;tal&lt;/span&gt;:&lt;span class=&#34;name&#34;&gt;replace&lt;/span&gt;=&lt;span class=&#34;string&#34;&gt;&#34;structure object/attribute/@@paragraphs&#34;&lt;/span&gt; /&amp;gt;
&lt;/pre&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Update:&lt;/strong&gt;  The view really ought to be registered twice: once
for basestring and once for NoneType.  I was too lazy to figure out the dotted
names for those (or check if zope.interface has external interface declarations
for them), so I registered it for &#34;*&#34;.  You should know that this makes the
view available for arbitrary objects (but won&#39;t work for most of them, since
they don&#39;t have a splitlines method), and that it is, sadly, accessible to
users who may try to hack your system by typing things like @@paragraphs in the
browser&#39;s address bar.  Ignas Mikalajūnas offers an &lt;a
  href=&#34;http://blog.pow.lt/2009/12/02/formatting-and-processing-text-in-tal-templates/&#34;&gt;alternative
  solution using TALES path adapters&lt;/a&gt;.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Custom traversal in Zope 3</title>
      <link>https://mg.pov.lt/blog/zope3-custom-traversal.html</link>
      <pubDate>Thu, 07 Jun 2007 20:02:58 +0300</pubDate>
      <author>marius@gedmin.as (Marius Gedminas)</author>
      <guid>https://mg.pov.lt/blog/zope3-custom-traversal.html</guid>
      <description>
&lt;p&gt; Certain things are not quite obvious in &lt;a
href=&#34;http://wiki.zope.org/zope3/FrontPage&#34;&gt;Zope 3&lt;/a&gt;. Custom traversal is one
of those: I always have to go and look at an example when I need it. Here&#39;s
the example: &lt;/p&gt;

&lt;p&gt; Say, you have a content object that provides IMySite and is exposed to the
web at /mysite.  You want to implement custom traversal for names under it,
e.g. have /mysite/mycalendar return some object specific to the user that&#39;s
currently logged in.  &lt;/p&gt;

&lt;p&gt; You need to provide an IBrowserPublisher adapter for (IMySite,
IBrowserRequest): &lt;/p&gt;

&lt;pre&gt;
&lt;span class=&#34;keyword&#34;&gt;from&lt;/span&gt; &lt;span class=&#34;name&#34;&gt;zope&lt;/span&gt;.&lt;span class=&#34;name&#34;&gt;component&lt;/span&gt; &lt;span class=&#34;keyword&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;name&#34;&gt;adapts&lt;/span&gt;, &lt;span class=&#34;name&#34;&gt;queryMultiAdapter&lt;/span&gt;
&lt;span class=&#34;keyword&#34;&gt;from&lt;/span&gt; &lt;span class=&#34;name&#34;&gt;zope&lt;/span&gt;.&lt;span class=&#34;name&#34;&gt;interface&lt;/span&gt; &lt;span class=&#34;keyword&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;name&#34;&gt;implements&lt;/span&gt;
&lt;span class=&#34;keyword&#34;&gt;from&lt;/span&gt; &lt;span class=&#34;name&#34;&gt;zope&lt;/span&gt;.&lt;span class=&#34;name&#34;&gt;publisher&lt;/span&gt;.&lt;span class=&#34;name&#34;&gt;interfaces&lt;/span&gt; &lt;span class=&#34;keyword&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;name&#34;&gt;NotFound&lt;/span&gt;
&lt;span class=&#34;keyword&#34;&gt;from&lt;/span&gt; &lt;span class=&#34;name&#34;&gt;zope&lt;/span&gt;.&lt;span class=&#34;name&#34;&gt;publisher&lt;/span&gt;.&lt;span class=&#34;name&#34;&gt;interfaces&lt;/span&gt;.&lt;span class=&#34;name&#34;&gt;browser&lt;/span&gt; &lt;span class=&#34;keyword&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;name&#34;&gt;IBrowserRequest&lt;/span&gt;, &lt;span class=&#34;name&#34;&gt;IBrowserPublisher&lt;/span&gt;

&lt;span class=&#34;keyword&#34;&gt;from&lt;/span&gt; &lt;span class=&#34;name&#34;&gt;mypackage&lt;/span&gt;.&lt;span class=&#34;name&#34;&gt;interfaces&lt;/span&gt; &lt;span class=&#34;keyword&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;name&#34;&gt;IMySite&lt;/span&gt;


&lt;span class=&#34;def&#34;&gt;class&lt;/span&gt; &lt;span class=&#34;name&#34;&gt;MySiteTraverser&lt;/span&gt;(&lt;span class=&#34;name&#34;&gt;object&lt;/span&gt;):
    &lt;span class=&#34;string&#34;&gt;&#34;&#34;&#34;Browser traverser for IMySite.&#34;&#34;&#34;&lt;/span&gt;

    &lt;span class=&#34;name&#34;&gt;adapts&lt;/span&gt;(&lt;span class=&#34;name&#34;&gt;IMySite&lt;/span&gt;, &lt;span class=&#34;name&#34;&gt;IBrowserRequest&lt;/span&gt;)
    &lt;span class=&#34;name&#34;&gt;implements&lt;/span&gt;(&lt;span class=&#34;name&#34;&gt;IBrowserPublisher&lt;/span&gt;)

    &lt;span class=&#34;def&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;name&#34;&gt;__init__&lt;/span&gt;(&lt;span class=&#34;name&#34;&gt;self&lt;/span&gt;, &lt;span class=&#34;name&#34;&gt;context&lt;/span&gt;, &lt;span class=&#34;name&#34;&gt;request&lt;/span&gt;):
        &lt;span class=&#34;name&#34;&gt;self&lt;/span&gt;.&lt;span class=&#34;name&#34;&gt;context&lt;/span&gt; = &lt;span class=&#34;name&#34;&gt;context&lt;/span&gt;
        &lt;span class=&#34;name&#34;&gt;self&lt;/span&gt;.&lt;span class=&#34;name&#34;&gt;request&lt;/span&gt; = &lt;span class=&#34;name&#34;&gt;request&lt;/span&gt;

    &lt;span class=&#34;def&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;name&#34;&gt;browserDefault&lt;/span&gt;(&lt;span class=&#34;name&#34;&gt;self&lt;/span&gt;, &lt;span class=&#34;name&#34;&gt;request&lt;/span&gt;):
        &lt;span class=&#34;string&#34;&gt;&#34;&#34;&#34;Return the default view of /mysite.&#34;&#34;&#34;&lt;/span&gt;
        &lt;span class=&#34;comment&#34;&gt;# XXX: use getDefaultViewName instead of assuming it&#39;s index.html&lt;/span&gt;
        &lt;span class=&#34;keyword&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;name&#34;&gt;self&lt;/span&gt;.&lt;span class=&#34;name&#34;&gt;context&lt;/span&gt;, (&lt;span class=&#34;string&#34;&gt;&#39;index.html&#39;&lt;/span&gt;, )

    &lt;span class=&#34;def&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;name&#34;&gt;publishTraverse&lt;/span&gt;(&lt;span class=&#34;name&#34;&gt;self&lt;/span&gt;, &lt;span class=&#34;name&#34;&gt;request&lt;/span&gt;, &lt;span class=&#34;name&#34;&gt;name&lt;/span&gt;):
        &lt;span class=&#34;string&#34;&gt;&#34;&#34;&#34;Traverse to /mysite/$name.&#34;&#34;&#34;&lt;/span&gt;
        &lt;span class=&#34;keyword&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;name&#34;&gt;name&lt;/span&gt; == &lt;span class=&#34;string&#34;&gt;&#39;mycalendar&#39;&lt;/span&gt;:
            &lt;span class=&#34;name&#34;&gt;mycalendar&lt;/span&gt; = ... &lt;span class=&#34;comment&#34;&gt;# TODO: do something to get the appropriate object&lt;/span&gt;
            &lt;span class=&#34;keyword&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;name&#34;&gt;mycalendar&lt;/span&gt;

        &lt;span class=&#34;comment&#34;&gt;# if self.context is a container of some sort,&lt;/span&gt;
        &lt;span class=&#34;comment&#34;&gt;# you&#39;ll have to add traversal to items here manually.&lt;/span&gt;

        &lt;span class=&#34;comment&#34;&gt;# fall back to views&lt;/span&gt;
        &lt;span class=&#34;name&#34;&gt;view&lt;/span&gt; = &lt;span class=&#34;name&#34;&gt;queryMultiAdapter&lt;/span&gt;((&lt;span class=&#34;name&#34;&gt;self&lt;/span&gt;.&lt;span class=&#34;name&#34;&gt;context&lt;/span&gt;, &lt;span class=&#34;name&#34;&gt;request&lt;/span&gt;), &lt;span class=&#34;name&#34;&gt;name&lt;/span&gt;=&lt;span class=&#34;name&#34;&gt;name&lt;/span&gt;)
        &lt;span class=&#34;keyword&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;name&#34;&gt;view&lt;/span&gt; &lt;span class=&#34;keyword&#34;&gt;is&lt;/span&gt; &lt;span class=&#34;keyword&#34;&gt;not&lt;/span&gt; &lt;span class=&#34;name&#34;&gt;None&lt;/span&gt;:
            &lt;span class=&#34;keyword&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;name&#34;&gt;view&lt;/span&gt;

        &lt;span class=&#34;comment&#34;&gt;# give up and return a 404 Not Found error page&lt;/span&gt;
        &lt;span class=&#34;keyword&#34;&gt;raise&lt;/span&gt; &lt;span class=&#34;name&#34;&gt;NotFound&lt;/span&gt;(&lt;span class=&#34;name&#34;&gt;self&lt;/span&gt;.&lt;span class=&#34;name&#34;&gt;context&lt;/span&gt;, &lt;span class=&#34;name&#34;&gt;name&lt;/span&gt;, &lt;span class=&#34;name&#34;&gt;request&lt;/span&gt;)
&lt;/pre&gt;

&lt;p&gt;Now register it in ZCML with&lt;/p&gt;

&lt;pre&gt;
    &amp;lt;&lt;span class=&#34;def&#34;&gt;view&lt;/span&gt;
        &lt;span class=&#34;name&#34;&gt;for&lt;/span&gt;=&lt;span class=&#34;string&#34;&gt;&#34;mypackage.interfaces.IMySite&#34;&lt;/span&gt;
        &lt;span class=&#34;name&#34;&gt;type&lt;/span&gt;=&lt;span class=&#34;string&#34;&gt;&#34;zope.publisher.interfaces.browser.IBrowserRequest&#34;&lt;/span&gt;
        &lt;span class=&#34;name&#34;&gt;provides&lt;/span&gt;=&lt;span class=&#34;string&#34;&gt;&#34;zope.publisher.interfaces.browser.IBrowserPublisher&#34;&lt;/span&gt;
        &lt;span class=&#34;name&#34;&gt;factory&lt;/span&gt;=&lt;span class=&#34;string&#34;&gt;&#34;mypackage.mymodule.MySiteTraverser&#34;&lt;/span&gt;
        &lt;span class=&#34;name&#34;&gt;permission&lt;/span&gt;=&lt;span class=&#34;string&#34;&gt;&#34;zope.Public&#34;&lt;/span&gt;
        /&amp;gt;
&lt;/pre&gt;

&lt;p&gt;Note that this is the regular &lt;tt class=&#34;def&#34;&gt;view&lt;/tt&gt; directive, not &lt;tt
class=&#34;keyword&#34;&gt;browser&lt;/tt&gt;:&lt;tt class=&#34;def&#34;&gt;view&lt;/tt&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Update:&lt;/strong&gt; Philipp von Weitershausen shows &lt;del&gt;&lt;a
href=&#34;http://www.z3lab.org/sections/blogs/philipp-weitershausen/2007_06_08_custom-traversal-with&#34;&gt;how
Grok simplifies
this&lt;/a&gt;&lt;/del&gt; (site disappeared; here&#39;s an &lt;a href=&#34;http://web.archive.org/web/20071112034040/http://www.z3lab.org/sections/blogs/philipp-weitershausen/2007_06_08_custom-traversal-with&#34;&gt;Internet Archive link&lt;/a&gt;).  Check out &lt;a href=&#34;http://grok.zope.org/&#34;&gt;the Grok website&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Update:&lt;/strong&gt; Added the missing __init__ method, thanks to Yuan
Hong for noticing.&lt;/p&gt;
</description>
    </item>
    
  </channel>
</rss>
