<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Peter's Blog - Nodes for kid</title>
    <link>http://www.petersblog.org/</link>
    <description>Nodes containing the tag kid</description>
    <item>
      <title>Cheetah template</title>
      <link>http://www.petersblog.org/node/view/1092</link>
      <description>&lt;p&gt;
&lt;a href="/tag/statcounter"&gt;statcounter&lt;/a&gt; tells me this site is linked from the &lt;a href="/tag/cheetah"&gt;cheetah&lt;/a&gt; template website on the &lt;a href="http://www.cheetahtemplate.org/whouses.html"&gt;Who uses it&lt;/a&gt; page. Yes, I do use it, I like it a lot. Since I started using &lt;a href="/tag/turbogears"&gt;TurboGears&lt;/a&gt; I have been using &lt;a href="/tag/kid"&gt;kid&lt;/a&gt; but only because TurboGears didn't originally support Cheetah (Cheetah support is being added via template plugins). 
&lt;/p&gt;
&lt;p&gt;
What I like most about cheetah is that most of the time things just work the way you think they will and you can get on with your coding, instead of working out why things don't work. kid also gives me that feeling but cheetah is more powerful: kid is mainly aimed at xml/html, it can do plain text but cheetah is truly agnostic. 
&lt;/p&gt;
&lt;p&gt;
Kid and Cheetah share the ${variable} method of replacing text in the template with python expressions. This is very easy and powerful, although it goes against the doctrine of separating code from display. In &lt;a href="/tag/django"&gt;django&lt;/a&gt; templates you can only substitute variables, you cannot call functions. I feel there is a fine line between python code that says 'object.name' and 'object.name()'. If you can explain one to a web designer, is it so hard to explain the other? Anyway, for my projects I &lt;i&gt;am&lt;/i&gt; the web designer. 
&lt;/p&gt;
&lt;p&gt;
If there is one thing I would change about kid it would be to somehow add an else term to the &lt;code&gt;if&lt;/code&gt; statement: I end up duplicating the test code and adding a &lt;code&gt;not&lt;/code&gt;. The more duplication there is, the less maintainable it is. 
&lt;/p&gt;
&lt;p&gt;
Kid templates can be previewed as html very nicely which is useful in creating the layout of a site. If you preview kid templates as html you get substitute text where your dynamic content will go (e.g. 'Users name goes here') whereas cheetah would show the python expression that generates the content (e.g. '$(UserName}'). However, once you start working on the dynamic content you can only preview by passing through the template engine anyway. One of my projects generates a complex table, the columns and rows being generated dynamically. The kid preview is pretty useless. 
&lt;/p&gt;
&lt;p&gt;
Kid's other advantage is that it will gripe if your xhtml is not well formed, e.g. you miss out a closing tag. This has saved me a couple of times but there are &lt;a href="http://validator.w3.org/"&gt;other tools to validate your output&lt;/a&gt;. 
&lt;/p&gt;
&lt;p&gt;
Apparently there is a tantalising new version of cheetah out. Must have a look, 
&lt;/p&gt;&lt;p&gt;Related Posts: &lt;a href="/tag/cheetah"&gt;cheetah&lt;/a&gt; &lt;a href="/tag/kid"&gt;kid&lt;/a&gt; &lt;a href="/tag/python"&gt;python&lt;/a&gt; &lt;a href="/tag/turbogears"&gt;turbogears&lt;/a&gt;&lt;/p&gt;</description>
      <guid>http://www.petersblog.org/node/view/1092</guid>
      <category domain="http://www.technorati.com/tag">cheetah</category>
      <category domain="http://www.technorati.com/tag">kid</category>
      <category domain="http://www.technorati.com/tag">python</category>
      <category domain="http://www.technorati.com/tag">turbogears</category>
    </item>
    <item>
      <title>TurboGears Mania</title>
      <link>http://www.petersblog.org/node/view/1072</link>
      <description>&lt;p&gt;
Coding away with &lt;a href="/tag/turbogears"&gt;TurboGears&lt;/a&gt; and found that glorious nirvava where whatever I tried Just Worked. &lt;a href="/tag/kid"&gt;Kid&lt;/a&gt;, &lt;a href="/tag/sqlobjects"&gt;SQLObjects&lt;/a&gt; and &lt;a href="/tag/cherrypy"&gt;cherrypy&lt;/a&gt; are nice and clean and turbogears has generated a nice boilerplate framework. Going through the code of the various librarys while debugging, there is magic in the way they are working but it is not causing me big troubles as the api's they present are nice and clean. &lt;a href="/tag/python"&gt;Python&lt;/a&gt; is such a lovely language I always felt it would be great for web development and now it feels like I have the tools. 
&lt;/p&gt;
&lt;p&gt;
I commented previously on SQLObjects support for introspection and I was wrong here as the help command (possibly docstrings in general?) is broken and generates an exception but the online documents are fairly comprehensive. 
&lt;/p&gt;
&lt;p&gt;
I have a heavy cold and hence had one of those tortured nights sleep with recurring dreams. I kept seeing Kid's XML element tree sitting in memory, branches being swapped in and out and the resulting document changing in wonderful ways. It was not a bad dream. I woke up thinking it was a great way to manipulate a document compared to primitive string substitution. I have never really tried DOM models before, being reluctant to use all that memory, but now that memory is cheap I shouldn't be so cautious. Playing with SAX parsers is a pain, if I have to write another state machine I'll scream. 
&lt;/p&gt;
&lt;p&gt;
Another discovery, the TurboGears command `tg-admin shell` somehow picked up &lt;a href="/node/620"&gt;IPython&lt;/a&gt; and I was able to play with the database api whil admiring the pretty colours. 
&lt;/p&gt;
&lt;p&gt;
It was nice until I tried porting a theme from php and ran into an annoying works-in-ie-but-not-firefox problem. There are some things that even the nicest development environments cannot help with. I tried using html-kit to clean up the template code and it is indeed easy to preview kid templates in a browser, they Just Work. 
&lt;/p&gt;
&lt;p&gt;
Tip for the Day: although kid templates are xml it is better to tell WingIDE they are html as it avoids a limitation of the xml syntax highlighting where it treats Processing Instructions as errors and marks most of the file as a syntax error, making the editor run pretty sluggishly. 
&lt;/p&gt;&lt;p&gt;Related Posts: &lt;a href="/tag/kid"&gt;kid&lt;/a&gt; &lt;a href="/tag/python"&gt;python&lt;/a&gt; &lt;a href="/tag/sqlobjects"&gt;sqlobjects&lt;/a&gt; &lt;a href="/tag/turbogears"&gt;turbogears&lt;/a&gt; &lt;a href="/tag/wingide"&gt;wingide&lt;/a&gt;&lt;/p&gt;</description>
      <guid>http://www.petersblog.org/node/view/1072</guid>
      <category domain="http://www.technorati.com/tag">kid</category>
      <category domain="http://www.technorati.com/tag">python</category>
      <category domain="http://www.technorati.com/tag">sqlobjects</category>
      <category domain="http://www.technorati.com/tag">turbogears</category>
      <category domain="http://www.technorati.com/tag">wingide</category>
    </item>
    <item>
      <title>TurboGears hang under Windows</title>
      <link>http://www.petersblog.org/node/view/1071</link>
      <description>&lt;p&gt;
Had &lt;a href="/tag/turbogears"&gt;turbogears&lt;/a&gt; hanging while debugging under &lt;a href="/tag/wingide"&gt;WingIDE&lt;/a&gt; but working fine from the  command line. One nice thing about using a decent debugger like WingIDE is I can press the pause button and see what it is doing when it appears to be hung. 
&lt;/p&gt;
&lt;p&gt;
It turns out it was in a kid function called 'relativize' that looks like this: 
&lt;/p&gt;
&lt;pre class="lazy"&gt;&lt;span class="line-numbers"&gt;   1 &lt;/span&gt; &lt;span class="Keyword"&gt;def&lt;/span&gt; &lt;span class="Entity"&gt;relativize&lt;/span&gt;(&lt;span class="Variable"&gt;self&lt;/span&gt;, &lt;span class="Variable"&gt;file&lt;/span&gt;, &lt;span class="Variable"&gt;path&lt;/span&gt;):
&lt;span class="line-numbers"&gt;   2 &lt;/span&gt;     &lt;span class="Keyword"&gt;from&lt;/span&gt; os.path &lt;span class="Keyword"&gt;import&lt;/span&gt; normpath, join, dirname, abspath, split, sep
&lt;span class="line-numbers"&gt;   3 &lt;/span&gt;     head, tail &lt;span class="Keyword"&gt;=&lt;/span&gt; (&lt;span class="MetaFunctionCallPy"&gt;dirname&lt;span class="MetaFunctionCallPy"&gt;(&lt;/span&gt;&lt;span class="MetaFunctionCallPy"&gt;&lt;span class="MetaFunctionCallPy"&gt;abspath&lt;span class="MetaFunctionCallPy"&gt;(&lt;/span&gt;&lt;span class="MetaFunctionCallPy"&gt;&lt;span class="Support"&gt;file&lt;/span&gt;&lt;/span&gt;&lt;span class="MetaFunctionCallPy"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="MetaFunctionCallPy"&gt;)&lt;/span&gt;&lt;/span&gt;, &lt;span class="String"&gt;&lt;span class="String"&gt;'&lt;/span&gt;&lt;span class="String"&gt;&lt;span class="String"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;)
&lt;span class="line-numbers"&gt;   4 &lt;/span&gt;     parts &lt;span class="Keyword"&gt;=&lt;/span&gt; &lt;span class="MetaFunctionCallPy"&gt;path.split&lt;span class="MetaFunctionCallPy"&gt;(&lt;/span&gt;&lt;span class="MetaFunctionCallPy"&gt;sep&lt;/span&gt;&lt;span class="MetaFunctionCallPy"&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line-numbers"&gt;   5 &lt;/span&gt;     paths &lt;span class="Keyword"&gt;=&lt;/span&gt; &lt;span class="Variable"&gt;self&lt;/span&gt;.paths
&lt;span class="line-numbers"&gt;   6 &lt;/span&gt;     &lt;span class="Keyword"&gt;while&lt;/span&gt; &lt;span class="Constant"&gt;1&lt;/span&gt;:
&lt;span class="line-numbers"&gt;   7 &lt;/span&gt;         &lt;span class="Keyword"&gt;if&lt;/span&gt; head &lt;span class="Keyword"&gt;in&lt;/span&gt; paths &lt;span class="Keyword"&gt;or&lt;/span&gt; head &lt;span class="Keyword"&gt;==&lt;/span&gt; &lt;span class="String"&gt;&lt;span class="String"&gt;'&lt;/span&gt;/&lt;span class="String"&gt;'&lt;/span&gt;&lt;/span&gt;:
&lt;span class="line-numbers"&gt;   8 &lt;/span&gt;             &lt;span class="Keyword"&gt;return&lt;/span&gt; &lt;span class="MetaFunctionCallPy"&gt;join&lt;span class="MetaFunctionCallPy"&gt;(&lt;/span&gt;&lt;span class="MetaFunctionCallPy"&gt;&lt;span class="Keyword"&gt;*&lt;/span&gt;parts&lt;/span&gt;&lt;span class="MetaFunctionCallPy"&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line-numbers"&gt;   9 &lt;/span&gt;         head, tail &lt;span class="Keyword"&gt;=&lt;/span&gt; &lt;span class="MetaFunctionCallPy"&gt;split&lt;span class="MetaFunctionCallPy"&gt;(&lt;/span&gt;&lt;span class="MetaFunctionCallPy"&gt;head&lt;/span&gt;&lt;span class="MetaFunctionCallPy"&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line-numbers"&gt;  10 &lt;/span&gt;         &lt;span class="MetaFunctionCallPy"&gt;parts.insert&lt;span class="MetaFunctionCallPy"&gt;(&lt;/span&gt;&lt;span class="MetaFunctionCallPy"&gt;&lt;span class="Constant"&gt;0&lt;/span&gt;, tail&lt;/span&gt;&lt;span class="MetaFunctionCallPy"&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;
It is trying to turn an absolute path into a relative path. The code was stuck in the while loop because 'head' was never 'in paths' or == '/'. The '/' would never match as this was windows and uses '\' as a file seperator, 'in paths' was broken because the path was in there a 'c:\Project\Path' but head was equal to 'C:\Project\Path': different capitalisation on the C. Tracing back, the upper case version was being returned by os.getcwd, the lower case version by the python package module. To cut a long story  short, I had set the initial debug directory in WingIDE to 'c:\Project\Path' with a lower case c and changing it to an upper case c in Wing fixed the problem. 
&lt;/p&gt;
&lt;p&gt;
Conclusion: Must bear in mind that kid may be flaky on Windows. 
&lt;/p&gt;
&lt;p&gt;
UPDATE: it broke again &lt;img alt="sad" src="/images/smileys/sad.png" /&gt; Resorted to fixing kid thusly: 
&lt;/p&gt;
&lt;pre class="lazy"&gt;&lt;span class="line-numbers"&gt;   1 &lt;/span&gt; &lt;span class="Keyword"&gt;def&lt;/span&gt; &lt;span class="Entity"&gt;relativize&lt;/span&gt;(&lt;span class="Variable"&gt;self&lt;/span&gt;, &lt;span class="Variable"&gt;file&lt;/span&gt;, &lt;span class="Variable"&gt;path&lt;/span&gt;):
&lt;span class="line-numbers"&gt;   2 &lt;/span&gt;     &lt;span class="Keyword"&gt;from&lt;/span&gt; os.path &lt;span class="Keyword"&gt;import&lt;/span&gt; normpath, join, dirname, abspath, split, sep
&lt;span class="line-numbers"&gt;   3 &lt;/span&gt;     &lt;span class="Keyword"&gt;from&lt;/span&gt; os.path &lt;span class="Keyword"&gt;import&lt;/span&gt; normcase  &lt;span class="Comment"&gt;&lt;span class="Comment"&gt;#&lt;/span&gt; pcw&lt;/span&gt;
&lt;span class="line-numbers"&gt;   4 &lt;/span&gt;     &lt;span class="Support"&gt;file&lt;/span&gt; &lt;span class="Keyword"&gt;=&lt;/span&gt; &lt;span class="MetaFunctionCallPy"&gt;normcase&lt;span class="MetaFunctionCallPy"&gt;(&lt;/span&gt;&lt;span class="MetaFunctionCallPy"&gt; &lt;span class="Support"&gt;file&lt;/span&gt;&lt;/span&gt;&lt;span class="MetaFunctionCallPy"&gt;)&lt;/span&gt;&lt;/span&gt;  &lt;span class="Comment"&gt;&lt;span class="Comment"&gt;#&lt;/span&gt; pcw&lt;/span&gt;
&lt;span class="line-numbers"&gt;   5 &lt;/span&gt;     head, tail &lt;span class="Keyword"&gt;=&lt;/span&gt; (&lt;span class="MetaFunctionCallPy"&gt;dirname&lt;span class="MetaFunctionCallPy"&gt;(&lt;/span&gt;&lt;span class="MetaFunctionCallPy"&gt;&lt;span class="MetaFunctionCallPy"&gt;abspath&lt;span class="MetaFunctionCallPy"&gt;(&lt;/span&gt;&lt;span class="MetaFunctionCallPy"&gt;&lt;span class="Support"&gt;file&lt;/span&gt;&lt;/span&gt;&lt;span class="MetaFunctionCallPy"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="MetaFunctionCallPy"&gt;)&lt;/span&gt;&lt;/span&gt;, &lt;span class="String"&gt;&lt;span class="String"&gt;'&lt;/span&gt;&lt;span class="String"&gt;&lt;span class="String"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;)
&lt;span class="line-numbers"&gt;   6 &lt;/span&gt;     parts &lt;span class="Keyword"&gt;=&lt;/span&gt; &lt;span class="MetaFunctionCallPy"&gt;path.split&lt;span class="MetaFunctionCallPy"&gt;(&lt;/span&gt;&lt;span class="MetaFunctionCallPy"&gt;sep&lt;/span&gt;&lt;span class="MetaFunctionCallPy"&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line-numbers"&gt;   7 &lt;/span&gt;     paths &lt;span class="Keyword"&gt;=&lt;/span&gt; [&lt;span class="MetaFunctionCallPy"&gt;normcase&lt;span class="MetaFunctionCallPy"&gt;(&lt;/span&gt;&lt;span class="MetaFunctionCallPy"&gt; strPath&lt;/span&gt;&lt;span class="MetaFunctionCallPy"&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class="Keyword"&gt;for&lt;/span&gt; strPath &lt;span class="Keyword"&gt;in&lt;/span&gt; &lt;span class="Variable"&gt;self&lt;/span&gt;.paths]  &lt;span class="Comment"&gt;&lt;span class="Comment"&gt;#&lt;/span&gt; pcw&lt;/span&gt;
&lt;span class="line-numbers"&gt;   8 &lt;/span&gt;     &lt;span class="Keyword"&gt;while&lt;/span&gt; &lt;span class="Constant"&gt;1&lt;/span&gt;:
&lt;span class="line-numbers"&gt;   9 &lt;/span&gt;         &lt;span class="Keyword"&gt;if&lt;/span&gt; head &lt;span class="Keyword"&gt;in&lt;/span&gt; paths &lt;span class="Keyword"&gt;or&lt;/span&gt; head &lt;span class="Keyword"&gt;==&lt;/span&gt; &lt;span class="String"&gt;&lt;span class="String"&gt;'&lt;/span&gt;&lt;span class="Constant"&gt;\\&lt;/span&gt;&lt;span class="String"&gt;'&lt;/span&gt;&lt;/span&gt;:
&lt;span class="line-numbers"&gt;  10 &lt;/span&gt;             &lt;span class="Keyword"&gt;return&lt;/span&gt; &lt;span class="MetaFunctionCallPy"&gt;join&lt;span class="MetaFunctionCallPy"&gt;(&lt;/span&gt;&lt;span class="MetaFunctionCallPy"&gt;&lt;span class="Keyword"&gt;*&lt;/span&gt;parts&lt;/span&gt;&lt;span class="MetaFunctionCallPy"&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line-numbers"&gt;  11 &lt;/span&gt;         head, tail &lt;span class="Keyword"&gt;=&lt;/span&gt; &lt;span class="MetaFunctionCallPy"&gt;split&lt;span class="MetaFunctionCallPy"&gt;(&lt;/span&gt;&lt;span class="MetaFunctionCallPy"&gt;head&lt;/span&gt;&lt;span class="MetaFunctionCallPy"&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line-numbers"&gt;  12 &lt;/span&gt;         &lt;span class="MetaFunctionCallPy"&gt;parts.insert&lt;span class="MetaFunctionCallPy"&gt;(&lt;/span&gt;&lt;span class="MetaFunctionCallPy"&gt;&lt;span class="Constant"&gt;0&lt;/span&gt;, tail&lt;/span&gt;&lt;span class="MetaFunctionCallPy"&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/pre&gt;&lt;p&gt;Related Posts: &lt;a href="/tag/kid"&gt;kid&lt;/a&gt; &lt;a href="/tag/python"&gt;python&lt;/a&gt; &lt;a href="/tag/turbogears"&gt;turbogears&lt;/a&gt;&lt;/p&gt;</description>
      <guid>http://www.petersblog.org/node/view/1071</guid>
      <category domain="http://www.technorati.com/tag">kid</category>
      <category domain="http://www.technorati.com/tag">python</category>
      <category domain="http://www.technorati.com/tag">turbogears</category>
    </item>
  </channel>
</rss>
