Peter's Blog

Redefining the Impossible

Items filed under cheetah


statcounter tells me this site is linked from the cheetah template website on the Who uses it page. Yes, I do use it, I like it a lot. Since I started using TurboGears I have been using kid but only because TurboGears didn't originally support Cheetah (Cheetah support is being added via template plugins).

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.

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 django 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 am the web designer.

If there is one thing I would change about kid it would be to somehow add an else term to the if statement: I end up duplicating the test code and adding a not. The more duplication there is, the less maintainable it is.

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.

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 other tools to validate your output.

Apparently there is a tantalising new version of cheetah out. Must have a look,


Filed under: cheetah kid python turbogears

2 Comments

I've been giving TurboGears a try as a means of reimplementing this blog in python. I have been trying django but I felt the need to try something else, mainly prompted by frustrations with the database api.

TurboGears is similar in the tools that it provides for web application development. It is essentially an amalgum of a number of existing python projects:

kid
a templating system based on XML.
cherrypy
web application framework, essentially maps urls to python method calls
SQLObject
an SQL database wrapper
Mochikit
a javascript library which I have tried before

Turbogears itself provides 'glue' to put these together. It has tools for creating project files, setting up and using the database etc. The TurboGears administration script creates a boilerplate application that can be running in no time. It all feels very similar to django, the main thing missing I can see is the administration screens but they are working on something called 'catwalk' which I think will do this. At the end of the day there are many database front ends that can provide administration (phpmyadmin, webmin mysql module etc) which are not so end-user friendly but good enough for me.

The librarys that turbogears has chosen appear to be very good in their own rigght. Their designs are clean and they are well documented. Each has greater depth than the django equivalents.

Kid looks powerful: it is an intersting mix of xml and python: your kid scripts can be used like python modules: they compile to .pyc files and so are presumably only parsed once. You can define xml snippets of boilerplate code, such as an html list, and call it like a function from elsewhere in your template. As it is XML based, if your template is not XML compliant the XML parser (expat at the lowest level) slaps your wrist. An interesting side effect of the pythonic nature of it is that if a problem appears in the python embedded in your template, Wing IDE's debugger will stop on that line. Useful! Kid does not support inheritance like django's template system, it effectively gives you macro templates that could be very powerful. The syntax is clearer than django, you can use python code inline )like cheetah) and the template substitution allows you to use the same substitution twice (if, for example, you want to use the same title string in two places, header and page title): a pedantic limitation in django. Looking through the documentation, Kid shows great attention to xhtml compliance and generation of conformant XHTML. This is not the greatest concern to me, I don't lose sleep over whether my XHTML is standards compliant, I am more worried about whether browsers will display it properly, but it is nice to know that someone somewhere has thought about all this for me.

SQLObject looks very clean and the objects can be introspected nicely. You work with the classes you define directly and not with meta classes that appear from nowhere. SQLObject has also introduced me to SQLite a really nice, simple SQL database library. This looks very solid, certainly good enough for development without the hastle of getting mysql running. It would probably be good enough for production use for me, if I can get it to run SQL dumps for backup (which I prefer to backing up binarys). Certainly I will be using it in the places where I can't be bothered to set up mysql (user's, permissions, passwords, yawn).

CherryPy: TurboGears creates enough boilerplate code that I haven't needed to look at the documents for this yet. It maps urls to method calls simply enough but one thing I like about django is the regular expression based url mapping which is totally flexible but there is nothing to stop me adding such a mapping layer.

I've ported the basics of my blog (the theme I use in drupal, lists of posts etc) to TurboGears. I had to study the Kid documentation to get the TurboGears generated code to use the head from the master.kid file so I could put my css import in one fixed place. By default the head here is ignored. The solution to this conundrum is to modify master.kid like this:

<head py:match="item.tag=='{http://www.w3.org/1999/xhtml}head'">
    <meta content="text/html; charset=UTF-8" http-equiv="content-type" py:replace="''"/>
    <title>Peter's Better Blog | ${strPageTitle}</title>
    <link rel="stylesheet" href="/static/css/style.css" />
</head>

i.e. turn it into a match template. I had the django inheritance thing in my head (not a million miles away from the drupal phptemplate engine) and I had to read the kid documentation to realise it simply works by sequentially replacing blocks of XML, in this case any later head block is replaced by the block above.


Add a comment

I didn't mention the Django templating system in my citique yesterday. It seems ok, as templating systems go, my favourite python templating system being cheetah.

The main advantage of cheetah that I have seen is that you can embed more python code in cheetah templates, or at least use more complex expressions to retrieve values. The django template system seems to restrict you to retrieving values of object properties: you cannot call functions as it complains about '(' characters. I think this is designed to force you to separate logic from presentation which is a Good Thing.

The Django system supports inheritance so a specific web page can inherit from a template describing the overall layout which is cool. I have yet to figure out how or whether it is possible to the equivalent of #include or import to put common sub-blocks in some pages (conceptually similar to a subroutine call). The 'load' tag might be the way.

The django system looks good enough to me to use in preference to cheetah: that's the coolest thing, I have the choice and I could even use both if I wanted.


Filed under: cheetah django python

1 Comment

Cheetah is a superlative templating library for python.


Filed under: cheetah

Add a comment

I've been contemplating some python web development. This is mainly for the following reasons:

  • I'd like my blog to have features for threading subjects based on keywords, a kind of related articles list. This would be dynamically updated, old articles could link to newer articles. This is possible in Drupal but the taxonomy system is laborious to configure through the web interface. There is a new keyword feature (folksonomies) but it appears to be a library for other modules to use. There are some modules that promise this kind of thing but they are not what I am looking for. The most important thing is that old articles are displayed with links to new articles, which involves messing around with themeing to add links to a cached page or figuring out how to flush the cache and put articles through a filter that would add the links.
  • I'd rather spend my limited programming time being creative with technologies I am already familiar with. I don't like php enough to want to learn it any more. I know and like python.
  • I don't want to spend my time trying to figure out how the Drupal code base works. Ok, I'm lazy and I have a short attention span and I'm not very interested in how it works.
  • If I do this as a spare time project I want to enjoy it, I don't want it to feel like a maintenance exercise. I can do that at work.
  • I have found that using librarys etc written by third partys can give you 95% of what you want, then you spend weeks trying to hack them to get the extra 5%. The only exception to this rule I can think of is the python standard library which is way cool.

So I looked at a few web application frameworks. This is a little lightweight and short on detail, I did most of it a few weeks ago and I didn't take notes.

cherrypy: Requires python 2.3 and my hosting service will only give me python 2.2 with cgi. I think generator functions are way cool and I'd love to use them. Do I stand any chance of getting my hosting service to upgrade? I'll email them and ask.

quixote: got the demo going, although I had to fix some of the urls within it as they appeared to be broken. It worked easily enough with cgi, the 1.3 version worked with python 2.2. However, again they have just released version 2 which has a couple of yield statements in it, limiting it python 2.3.

webware: I don't think I could see the advantage of 'servlets' and their web site (presumably powered by webware but it only says 'python powered') is not an impressive display of it's capabilities.

zope/plone: I've toyed with zope in the past (version 2) and found it's learning curve to be almighty. It may be very capable but you have to learn the zope way to do everything. The developers seem to be concentrating on inventing new object-orientated paradigms rather than keeping things simple and I hate huge complex object models. I don't like the web-based source editor (what, no syntax highlighting?: although I could use mozex and edit in vim). Also, non-cgi.

I was most interested in quixote until I came to the python 2.3 stumbling block with the new version 2. I don't want to settle for an old version. This led me on to think about what these frameworks actually give me:

  • map urls to class/method calls
    • big deal
  • session management
    • do I need it for my simple purposes?
  • templating systems
  • interface to cgi/mod_python/fastcgi/whatever
    • I can only have cgi anyway
  • easy form generation
    • classes to build the contents of a form. How many forms will I need? Can't templates do this?
  • already used on the internet and exposed to hackers
    • lets not be too ambitious with what we do. Keep drupal in the background for data entry.
  • learning curves

Which has led me to... straight cgi. Run my own scripts from cgi, using the cgi module in the standard python library to get the url parameters and generate a nice error page when things go wrong. I can get it going easily enough and below, with just a few hours hacking, is something that can display nodes from the drupal database. The output is themed through the Cheetah template engine and gives me the same look as my drupal theme. Given that it is only cgi it is not massively scalable, but I understand every line of it and that means a lot in terms of development time. Given that it generates pages that look like the drupal pages, I can chop and change, leaving some bits to drupal (data entry) and others in python (presentation). It's a lash up but so what?

The main challenge is porting my wilki module to python, particularly the geshi syntax highlighting.

I am not planning to rewrite Drupal and I probably won't release Yet Another Python Web Framework. I may not even finish it. It is something for me to play with.

   1  #!/usr/bin/python
   2  #
   3  import Cheetah.Template
   4  import cgi
   5  import cgitb; cgitb.enable()
   6  import time
   7  import datetime
   8  import os
   9  import pdo
  10  
  11  def ThemeAndOutput( strPageTitle, strContent, oParams={}):
  12      "Theme the site"
  13  
  14      strSideBar = """
  15      <div class="block">
  16      <h2>Reports</h2>
  17      <ul>
  18          <li><a href="Intranet.cgi">Drupal Emulator</a></li>
  19      </ul>
  20      </div>"""
  21  
  22      oDict = {
  23          'Root': '/SMB',
  24          'Url': '/Intranet/Intranet.cgi',
  25          'Title': 'Drupal Emulator',
  26          'Slogan': 'There are no Problems, only Challenges',
  27          'PrimaryLinks': [ '<a href="http://intranet.org">Intranet</a>',
  28                              '<a href="http://www.google.co.uk">Google</a>'],
  29          'PageTitle': strPageTitle,
  30          'SideBar': strSideBar,
  31          'Footer': 'Copyright 2005 Peter Wilkinson'
  32      }
  33  
  34      #
  35      # Read page template and shove in the content.
  36      #
  37      strTemplate = open( 'PageTemplate.html').read() % { 'Content': strContent}
  38  
  39      #
  40      # Run template and content through cheetah in one go.
  41      # Is this faster? Doubt it.
  42      #
  43      oHtml = Cheetah.Template.Template( strTemplate, [oDict, oParams])
  44  
  45      print str(oHtml)
  46  
  47  def MainPage( oForm):
  48      "Main welcome page: tell user what is going on"
  49  
  50      #
  51      # Determine how many links to show.
  52      #
  53      strFrom = oForm.getfirst( 'from')
  54      if strFrom == None:
  55          strLimit = ' LIMIT 10'
  56      else:
  57          try:
  58              nLimit = int(strFrom)
  59              strLimit = ' LIMIT %d, 10' % nLimit
  60          except:
  61              strLimit = ' LIMIT 10'
  62  
  63      c = pdo.connect( 'Module=MySQLdb;user=drupal;passwd=secret;db=drupal')
  64      rs = c.open( 'SELECT * FROM node ORDER BY created DESC %s' % strLimit)
  65  
  66      strTitles = []
  67      while rs.next():
  68          strTitles.append( '<a href="Intranet.cgi?node=%s">%s</a>' %
  69                (rs.fields['nid'].value, rs.fields['title'].value))
  70  
  71      strPage = """
  72  <ul>
  73  #for $strTitle in $titles
  74  <li>$strTitle</li>
  75  #end for
  76  </ul>
  77      """
  78  
  79      ThemeAndOutput( "Welcome", strPage, { 'titles': strTitles})
  80  
  81  def NodePage( oForm):
  82      "Display a node"
  83  
  84      strNode = oForm.getfirst( 'node')
  85      if strNode == None:
  86          ErrorPage()
  87          return
  88      else:
  89          try:
  90              nNode = int(strNode)
  91          except:
  92              ErrorPage()
  93              return
  94  
  95      c = pdo.connect( 'Module=MySQLdb;user=drupal;passwd=secret;db=drupal')
  96      rs = c.open( 'SELECT * FROM node WHERE nid = %d' % nNode)
  97  
  98      if rs.next():
  99          strTitle = rs.fields['title'].value
 100          strBody = rs.fields['body'].value
 101      else:
 102          ErrorPage()
 103          return
 104  
 105      strPage = """
 106  <h2>$strTitle</h2>
 107  
 108  <pre>
 109  $strBody
 110  </pre>
 111      """
 112  
 113      ThemeAndOutput( strTitle, strPage,
 114            { 'strTitle': strTitle, 'strBody': strBody})
 115  
 116  def ErrorPage():
 117      strPage = """<p>There has been some kind of navigation error, the link
 118  you just clicked is broken</p>
 119  <p>Better <a href="mailto:someone@somewhere.com">complain about it</a>.</p>
 120      """
 121  
 122      ThemeAndOutput( "Drupal emulator", strPage)
 123  
 124  oForm=cgi.FieldStorage()
 125  
 126  node = oForm.getfirst( 'node')
 127  if node:
 128      NodePage( oForm)
 129  else:
 130      MainPage( oForm)

The page template is kept in a seperate file. It is based on the phptemplate of my drupal theme and was ported over in less than an hour. Theming engines? A specialisation of templates.

   1  Content-Type: text/html
   2  
   3  <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
   4   "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
   5  <html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
   6  <head>
   7  <title>$Title</title>
   8  <meta http-equiv="Content-Style-Type" content="text/css"/>
   9  <style type="text/css">@import url(style.css);</style>
  10  </head>
  11  <body>
  12      <div id="headerleft">
  13      </div>
  14      <div id="headermain">
  15          <div id="ie6hack">
  16          </div>
  17      </div>
  18      <div id="headertitle">
  19          <h1>
  20              <a href="$Url" title="$Title">
  21              $Title</a>
  22          </h1>
  23      </div>
  24      <div class="slogan">
  25          $Slogan
  26      </div>
  27      <div id="logo">
  28          <a href="$Url" title="$Title">
  29              <img src="ITL.gif"/>
  30          </a>
  31      </div>
  32      <div id="headerright">
  33      </div>
  34  #if len($PrimaryLinks) > 0
  35      <div id="primarylinks">
  36          <ul>
  37  #for $PrimaryLink in $PrimaryLinks
  38              <li>$PrimaryLink</li>
  39  #end for
  40          </ul>
  41      </div>
  42  #end if
  43  
  44      <div id="ie5forcemargininsidehack">
  45          <div id="main">
  46              <div class="tab">
  47                  <div class="tabbackground">
  48                      <div class="tableft">
  49                          <h3>
  50                              $PageTitle
  51                          </h3>
  52                      </div>
  53                  </div>
  54              </div>
  55              <div class="tabbody">
  56                  <div class="ieisbuggy">
  57                  </div>
  58                  <div id="content">
  59                      %(Content)s
  60                  </div>
  61                  <div class="ieisbuggy">
  62                  </div>
  63              </div>
  64          </div>
  65          <div id="footer">
  66              <div class="footerleft">
  67                  <p>
  68                  $Footer
  69                  </p>
  70              </div>
  71          </div>
  72      </div>
  73      <div id="sidebarright">
  74          <div id="sidebar">
  75              <div class="sidebarbox">
  76                  $SideBar
  77              </div>
  78          </div>
  79          <div id="sidebarbottom">
  80          </div>
  81      </div>
  82  </body>

Add a comment

The following is valid python:

def Try(
    a,
    b,
    c
    ):
    print a,b,c

Try( 1,2,3)

This was almost useful to me because I can almost generate the python source in python itself using a Cheetah template:

   1  import Cheetah.Template
   2  
   3  strTemplate = """
   4  def Try(
   5  #for $arg in $args
   6      $arg,
   7  #end for
   8      ):
   9  #for $arg in $args
  10      print $arg,
  11  #end for
  12      print
  13  """
  14  
  15  oDict = { 'args': args}
  16  strFile = Cheetah.Template.Template( strTemplate, [oDict])

This would generate the following which won't work because the last arg has a comma after it:

def Try(
    a,
    b,
    c,
    ):
    print a,
    print b,
    print c,
    print

There may be a way to suppress it in conditional logic but then it gets messy. The simple solution is to process the arguments into a single string before passing them to Cheetah:

   1  import Cheetah.Template
   2  
   3  strTemplate = """
   4  def Try( $argstring):
   5      print $argstring
   6  """
   7  
   8  argstring = ','.join( args)
   9  oDict = { 'argstring': argstring}
  10  strFile = Cheetah.Template.Template( strTemplate, [oDict])

I like Cheetah but sometimes I have to be careful that a simple bit of python won't do the trick more easily:

strBlah = """
def Try( %s):
    print %s
""" % (','.join( args), ','.join( args))

Arguably better as it avoids duplication:

strBlah = """
def Try( %(args)s):
    print %(args)s
""" % { 'args': ','.join( args)}

Conclusion: keep it simple.


Filed under: cheetah python

Add a comment

Wanted to install the wonderful Cheetah Template Library on Ubuntu Linux and was rewarded with this:

> sudo python setup.py install
Traceback (most recent call last):
  File "setup.py", line 10, in ?
    import SetupTools
  File "/home/pcw/download/Cheetah-0.9.16a2/SetupTools.py", line 23, in ?
    from distutils.core import setup
ImportError: No module named distutils.core

Found this article which told me to install the python-dev package. Apparently the Ubuntu folk have decided to mess around with the Python standard library and chop it into small bits. I guess they enjoy searching through package lists more than I do.


Filed under: cheetah linux python ubuntu

1 Comment

Under Windows the following python uses the Win32 extensions to launch whatever default html browser you have showing the appropriate html file:

import win32api

strPathToFile = "c:\\path\\for\\file.html"

win32api.ShellExecute( 0, "Open", strPathToFile, None, None, 0)

This is coolest when combined with the Cheetah Template Library:

   1  import Cheetah.Template
   2  
   3  #
   4  # Define report template. This is mostly html, the $ stuff will be
   5  # replaced by Cheetah.
   6  #
   7  strTemplate = """
   8  <html>
   9  <head>
  10  <title>$title</title>
  11  <head>
  12  <body>
  13  Hello $name, how are you today?
  14  </body>
  15  </html>
  16  """
  17  
  18  #
  19  # Build a dictionary of the $ symbols above and what should be displayed instead
  20  #
  21  oDict = { 'title': "This is my title", 'name': 'Peter'}
  22  
  23  #
  24  # Cheetah does it's magic
  25  #
  26  oHtml = Cheetah.Template.Template( strTemplate, [oDict])
  27  
  28  #
  29  # Write html to file and display it.
  30  #
  31  open( 'c:\\tmp\\file.html', 'wt').write( str(oHtml))
  32  win32api.ShellExecute( 0, "Open", 'c:\\tmp\\file.html', None, None, 0)

Cheetah is very powerful. The following code demonstrates a few features:

  • can use for loops to generate the rows of a table
  • instances of classes can be passed into cheetah and it can access member variables or call member functions
  • it tends to work first time the way you think it will.
   1  #
   2  # Show test report
   3  #
   4  
   5  import Cheetah.Template
   6  
   7  strTemplate = """
   8  $wiffle.blub
   9  $wiffle.nub
  10  $wiffle.grub()
  11  <table>
  12  <tr>
  13  #for $awiff in $wiffles
  14  <td>$awiff.blub</td>
  15  <td>$awiff.nub</td>
  16  <td>$awiff.grub()</td>
  17  #end for
  18  </tr>
  19  </table>
  20  """
  21  
  22  class Wiff:
  23      def __init__( self):
  24          self.blub = 'blublub'
  25          self.nub = 'nubnubnub'
  26      def grub( self):
  27          return 'i am grub'
  28  
  29  oDict = { 'wiffle': Wiff(), 'wiffles': [ Wiff(), Wiff(), Wiff()] }
  30  
  31  oHtml = Cheetah.Template.Template( strTemplate, [oDict])
  32  print str(oHtml)

Filed under: cheetah python windows

Add a comment

Been playing with Pythoncard. This is a wrapper library for wxpython that simplifies using it somewhat. The best feature of it is probably the resource manager that provides a visual GUI editor for dropping controls and assigning properties, vb style. It is clean and stable.

I've written a utility that uses:

and it all works together sweetly. The application generates an html report and uses the HtmlWindow control to display it an also print it, complete with graphics.

Problems encountered:

  • The BitmapCanvas component is supposed to support the display of PIL images directly but it did not work for me. I had to hack bitmapcanvas.py as follows:
       1      def drawBitmapScaled(self, aBitmap, xy, size, transparency=1):
       2          if isinstance(aBitmap, graphic.Bitmap):
       3              img = wx.ImageFromBitmap(aBitmap.getBits())
       4          elif isinstance(aBitmap, wx.Bitmap):
       5              img = wx.ImageFromBitmap(aBitmap)
       6          elif isinstance(aBitmap, wx.Image):
       7              img = aBitmap
       8          # pcw elif PIL_FOUND and isinstance(aBitmap, Image.Image):
       9          elif PIL_FOUND:
      10              img = graphic.PILToImage(aBitmap)
      11          elif NUMERIC_FOUND and isinstance(aBitmap, ArrayType):
      12              img = graphic.numericArrayToImage(aBitmap)
      13          else:
      14              return
    
    The isinstance call was returning PIL.Image.Image so the above test was failing. I put a similar change in DrawBitmap
  • The HtmlWindow control does not seem to support coloured fonts. The following:
    <span style="color:#ff0000;">Bin It</span>.
    
    comes out black instead of red. Maybe it doesn't support .CSS.

Filed under: cheetah python wxpython

Add a comment

As promised, how to do photo blogging from mobile phone. Actually this should support submitting plain text blog posts from any email source as I want to use the same mechanism to post blog entries from work that are for public display, bypassing the firewall. This recipe works with UK O2 MMS messages.

The first line of text in the email message becomes the title of the post, the following lines become the body.

Requirements:

  • Exim (or any MTA that supports forward files)

  • Python Desktop Server (or any server that supports MetaWeblogAPI or Blogger API, although you have to hack the image upload yourself, depending on the server).

  • Python (or you can rewrite it all in some other language)

Exim has to be set up to allow .forward files to process email. The .forward file should look like this:

# Exim filter
logfile ~/.forward.log

if $header_subject is "Multimedia message"
then
    pipe "/home/me/MailBot.py"
    seen finish
endif

This will direct emails with this subject line (i.e. UK O2 MMS messages) to the python script that does the hard work. This script is as follows and has to be made executable by the exim process:

#!/usr/bin/python
#
# Take an email message from stdin and post it to PyDS Blog.
# This works with UK O2 media messaging.
#
import smtplib
import sys
import email
import xmlrpclib

strMobileNumber = "0123456"
strXMLRPCUser = "fred"
strXMLRPCPassword = "xxx"

#
# Read email message piped in by exim filter from stdin.
#
strMsg = ""

for strLine in sys.stdin.readlines():
    
strMsg += strLine

oEmail = email.message_from_string( strMsg)

#
# Mobile number is in from address on O2.
# Stop people posting pr0n on my web site
# Hack this to add extra senders or security.
#
if not( oEmail'from'">'from'.find( strMobileNumber) >= 0:
    
#
    
# Does not appear to be from me.
    
#
    
sys.exit()

#
# Run email through parser, collecting all text/plain parts.
#
body = ""
strImages = []

for oPart in oEmail.walk():
    
#
    
# Look for plain text
    
#
    
if oPart.get_content_type() == 'text/plain':
        
if oPart.is_multipart() == False:
            
strPart = oPart.get_payload( decode=True)

            
#
            
# Ignore blurb added to message by o2.
            
#
            
if strPart.find( "This is a Media Message from O2") >= 0:
                
continue

            
body += strPart

    
#
    
# Look for images
    
#
    
if oPart.get_content_type() == 'image/jpeg':
        
strImage = oPart.get_payload( decode=True)
        
strFileName = oPart'Content-Location'">'Content-Location'
        
#
        
# Hack to pyds dir
        
#
        
open( '/home/me/.PyDS/www/images/' + strFileName, 'wb').write( strImage)
        
strImages.append( "$macros.imageTag( 'images/%s')\n" % strFileName)

#
# The first line is the title. The rest is the body.
#
strBody = body.split( '\n')
strTitle = strBody0">0
strBody = "".join( strImages) + "\n".join( strBody1:">1:)

#
# Open xmlrpc link to pyds.
#
oPyDS = xmlrpclib.ServerProxy( 'http://localhost:4334/RPC2')

#
# Get recent posts and build a map of title->postid.
#
oPosts = oPyDS.metaWeblog.getRecentPosts( '', strXMLRPCUser, strXMLRPCPassword, 1000)

oExistingPosts = {}

for oPost in oPosts:
    
oExistingPostsoPost['title'">oPost['title'] = oPost'postid'">'postid'

#
# Build parameters for post using unicode to pass weird characters.
#
oPost'title'">'title' = unicode( strTitle, 'ISO-8859-1')
oPost'description'">'description' = unicode( strBody, 'ISO-8859-1')

#
# See if this is a new post from it's unique title.
# If it is unique then post it as a new article.
#
if not oExistingPosts.has_key( strTitle):
    
oPyDS.metaWeblog.newPost( '', strXMLRPCUser, strXMLRPCPassword, oPost, 1)
else:
    
#
    
# Edit existing post
    
#
    
oPyDS.metaWeblog.editPost( oExistingPostsstrTitle">strTitle, strXMLRPCUser, strXMLRPCPassword, oPost, 1)

I had to make a small hack in Python Desktop Server. Posted articles default to either raw html or strict structured text but the image link requires structured text + cheetah. I had to edit the file MetaWebWeblogAPI.py to change the two lines that said:

structured = 2

to

structured = 1

ToDo:

  • Try to get text to wrap round image

  • Save up to pay my mobile bill


Add a comment