Commit 4b23c2f9 authored by Sam Ruby's avatar Sam Ruby

Docs and more Python backwards compatibility

parent 366fe8b3
Sam Ruby <>
This codebase represents a radical refactoring of Planet 2.0, which lists
the following authors:
Scott James Remnant <>
Jeff Waugh <>
Installing Planet
You'll need at least Python 2.2 installed on your system, we recommend
Python 2.4 though as there may be bugs with the earlier libraries.
Everything Pythonesque Planet needs should be included in the
First you'll need to extract the files into a folder somewhere.
I expect you've already done this, after all, you're reading this
file. You can place this wherever you like, ~/planet is a good
choice, but so's anywhere else you prefer.
This is very important: from within that directory, type the following
This should take anywhere from a half a second to ten seconds to execute.
No network connection is required, and it cleans up after itself. If it
completes with an "OK", you are good to go. Otherwise stopping here and
inquiring on the mailing list is a good idea as it can save you lots of
frustration down the road.
Make a copy of one of the 'ini' the files in the 'examples' subdirectory,
and put them wherever you like; I like to use the Planet's name (so
~/planet/debian), but it's really up to you.
Edit the config.ini file in this directory to taste, it's pretty
well documented so you shouldn't have any problems here. Pay
particular attention to the 'output_dir' option, which should be
readable by your web server. If the directory you specify in your
'cache_dir' exists, make sure that it is empty.
Run it: python pathto/config.ini
You'll want to add this to cron, make sure you run it from the
right directory.
vi. (Optional)
Tell us about it! We'd love to link to you on :-)
vii. (Optional)
Build your own themes, templates, or filters! And share!
Template files
The template files used are given as a whitespace separated list in the
'template_files' option in config.ini. The extension at the end of the
file name indicates what processor to use. Templates may be implemented
using htmltmpl, xslt, or any programming language.
The final extension is removed to form the name of the file placed in the
output directory.
HtmlTmpl files
Reading through the example templates is recommended, they're designed to
pretty much drop straight into your site with little modification
Inside these template files, <TMPL_VAR xxx> is replaced with the content
of the 'xxx' variable. The variables available are:
name .... } the value of the equivalent options
link .... } from the [Planet] section of your
owner_name . } Planet's config.ini file
owner_email }
url .... link with the output filename appended
generator .. version of planet being used
date .... { your date format
date_iso ... current date and time in { ISO date format
date_822 ... { RFC822 date format
There are also two loops, 'Items' and 'Channels'. All of the lines of
the template and variable substitutions are available for each item or
channel. Loops are created using <TMPL_LOOP LoopName>...</TMPL_LOOP>
and may be used as many times as you wish.
The 'Channels' loop iterates all of the channels (feeds) defined in the
configuration file, within it the following variables are available:
name .... value of the 'name' option in config.ini, or title
title .... title retreived from the channel's feed
tagline .... description retreived from the channel's feed
link .... link for the human-readable content (from the feed)
url .... url of the channel's feed itself
Additionally the value of any other option specified in config.ini
for the feed, or in the [DEFAULT] section, is available as a
variable of the same name.
Depending on the feed, there may be a huge variety of other
variables may be available; the best way to find out what you
have is using the 'planet-cache' tool to examine your cache files.
The 'Items' loop iterates all of the blog entries from all of the channels,
you do not place it inside a 'Channels' loop. Within it, the following
variables are available:
id .... unique id for this entry (sometimes just the link)
link .... link to a human-readable version at the origin site
title .... title of the entry
summary .... a short "first page" summary
content .... the full content of the entry
date .... { your date format
date_iso ... date and time of the entry in { ISO date format
date_822 ... { RFC822 date format
If the entry takes place on a date that has no prior entry has
taken place on, the 'new_date' variable is set to that date.
This allows you to break up the page by day.
If the entry is from a different channel to the previous entry,
or is the first entry from this channel on this day
the 'new_channel' variable is set to the same value as the
'channel_url' variable. This allows you to collate multiple
entries from the same person under the same banner.
Additionally the value of any variable that would be defined
for the channel is available, with 'channel_' prepended to the
name (e.g. 'channel_name' and 'channel_link').
Depending on the feed, there may be a huge variety of other
variables may be available; the best way to find out what you
have is using the 'planet-cache' tool to examine your cache files.
There are also a couple of other special things you can do in a template.
- If you want HTML escaping applied to the value of a variable, use the
<TMPL_VAR xxx ESCAPE="HTML"> form.
- If you want URI escaping applied to the value of a variable, use the
<TMPL_VAR xxx ESCAPE="URI"> form.
- To only include a section of the template if the variable has a
non-empty value, you can use <TMPL_IF xxx>....</TMPL_IF>. e.g.
<TMPL_IF new_date>
<h1><TMPL_VAR new_date></h1>
You may place a <TMPL_ELSE> within this block to specify an
alternative, or may use <TMPL_UNLESS xxx>...</TMPL_UNLESS> to
perform the opposite.
This diff is collapsed.
Planet is a flexible feed aggregator. It downloads news feeds published by
web sites and aggregates their content together into a single combined feed,
latest news first. This version of Planet is named Venus as it is the
second major version. The first version is still in wide use and is
also actively being maintained.
It uses Mark Pilgrim's Universal Feed Parser to read from CDF, RDF, RSS and
Atom feeds; Leonard Richardson's Beautiful Soup to correct markup issues;
and Tomas Styblo's templating engine to output static files in any
format you can dream up.
To get started, check out the INSTALL file in this directory. If you have any
questions or comments, please don't hesitate to use the planet mailing list:
Keywords: feed, blog, aggregator, RSS, RDF, Atom, OPML, Python
DeWitt Clinton - Mac OSX
Mary Gardiner - PythonPath
This codebase represents a radical refactoring of Planet 2.0, which lists
the following contributors:
Patches and Bug Fixes
Chris Dolan - fixes, exclude filtering, duplicate culling
David Edmondson - filtering
Lucas Nussbaum - locale configuration
David Pashley - cache code profiling and recursion fixing
Gediminas Paulauskas - days per page
Spycyroll Maintainers
Vattekkat Satheesh Babu
Richard Jones
Garth Kidd
Eliot Landrum
Bryan Richard
* Enable per-feed adjustments
The goal is to better cope with feeds that don't have dates or ids or
consitently encode or escape things incorrectly.
* Expire feed history
The feed cache doesn't currently expire old entries, so could get
large quite rapidly. We should probably have a config setting for
the cache expiry, the trouble is some channels might need a longer
or shorter one than others.
* Allow display normalisation to specified timezone
Some Planet admins would like their feed to be displayed in the local
timezone, instead of UTC.
<svg xmlns="" viewBox="0 0 1280 1024" xmlns:xlink="">>
<g id="feed">
<path d="M10,15l75,0l0,75l-75,0z" fill="#F80"
stroke-linejoin="round" stroke-width="20" stroke="#F80"/>
<circle cx="15" cy="82" r="6" fill="#FFF"/>
<path d="M35,82s0-20-20-20 M55,82s0-40-40-40 M75,82s0-60-60-60"
stroke-linecap="round" stroke-width="12" stroke="#FFF" fill="none"/>
<g id="entry">
<g fill="none">
<ellipse stroke="#689" rx="3" ry="22"/>
<ellipse stroke="#eb4" rx="3" ry="22" transform="rotate(-66)"/>
<ellipse stroke="#8ac" rx="3" ry="22" transform="rotate(66)"/>
<circle stroke="#451" r="22"/>
<g fill="#689" stroke="#FFF">
<circle fill="#8ac" r="6.5"/>
<circle cy="-22" r="4.5"/>
<circle cx="-20" cy="9" r="4.5"/>
<circle cx="20" cy="9" r="4.5"/>
<g id="node" stroke="none">
<circle r="18" fill="#049"/>
<path d="M-14,7a16,16,0,0,1,22-21a15,15,0,0,0-14,2a3,3,0,1,1-5,5
a15,15,0,0,0-3,14" fill="#FFF"/>
<path d="M-14-6a44,62,0,0,0,28,0l0,12a44,62,0,0,0-28,0z"
fill="#049" id="arc"/>
<rect height="1024" width="1280" fill="#0D0"/>
<use xlink:href="#feed" x="220" y="30"/>
<use xlink:href="#feed" x="150" y="60"/>
<use xlink:href="#feed" x="100" y="100"/>
<use xlink:href="#feed" x="60" y="150"/>
<use xlink:href="#feed" x="30" y="220"/>
<g fill="#F00" stroke-linejoin="round" stroke-width="12" stroke="#F88">
<path d="M50,800l0,180l1000,0l0-180z" fill="#FFF"/>
<path d="M150,330l400,0l0,300l-400,0z"/>
<path d="M750,200l200,0 l0,110l100,0l0,60l-100,0 l0,40l100,0l0,60l-100,0
l0,40l100,0l0,60l-100,0 l0,130l70,70l-340,0l70,-70z"/>
<path d="M1080,360l100,0l0,-70l-30,-30l-70,0z" fill="#FFF"/>
<path d="M1180,290l-30,0l0,-30" fill="none" stroke="#000"/>
<use xlink:href="#feed" x="1080" y="380"/>
<g transform="translate(1080,500)">
<use xlink:href="#arc" transform="translate(76,50) rotate(90)"/>
<use xlink:href="#arc" transform="translate(50,35) rotate(-30)"/>
<use xlink:href="#arc" transform="translate(50,65) rotate(30)"/>
<use xlink:href="#node" transform="translate(24,50)"/>
<use xlink:href="#node" transform="translate(76,80)"/>
<use xlink:href="#node" transform="translate(76,20)"/>
<path d="M260,150s100,60,90,280 M170,270s150,0,180,120
stroke="#000" fill="none" stroke-width="40"/>
<ellipse cx="350" cy="368" fill="#FFF" rx="80" ry="30"/>
<ellipse cx="850" cy="238" fill="#FFF" rx="80" ry="30"/>
<g font-size="32" fill="#FFF" text-anchor="middle">
<text x="350" y="380" fill="#F00">Spider</text>
<text x="350" y="460">Universal Feed Parser</text>
<text x="350" y="530">BeautifulSoup</text>
<text x="350" y="600">Reconstitute</text>
<text x="350" y="750">Filter(s)</text>
<text x="850" y="250" fill="#F00">Splice</text>
<text x="950" y="350">Template</text>
<text x="950" y="450">Template</text>
<text x="950" y="550">Template</text>
<text x="1126" y="330" fill="#000">HTML</text>
<use xlink:href="#entry" x="100" y="900"/>
<use xlink:href="#entry" x="180" y="950"/>
<use xlink:href="#entry" x="200" y="850"/>
<use xlink:href="#entry" x="290" y="920"/>
<use xlink:href="#entry" x="400" y="900"/>
<use xlink:href="#entry" x="470" y="840"/>
<use xlink:href="#entry" x="500" y="930"/>
<use xlink:href="#entry" x="570" y="870"/>
<use xlink:href="#entry" x="620" y="935"/>
<use xlink:href="#entry" x="650" y="835"/>
<use xlink:href="#entry" x="690" y="900"/>
<use xlink:href="#entry" x="720" y="835"/>
<use xlink:href="#entry" x="730" y="950"/>
<use xlink:href="#entry" x="760" y="900"/>
<use xlink:href="#entry" x="790" y="835"/>
<use xlink:href="#entry" x="800" y="950"/>
<use xlink:href="#entry" x="830" y="900"/>
<use xlink:href="#entry" x="860" y="835"/>
<use xlink:href="#entry" x="870" y="950"/>
<use xlink:href="#entry" x="900" y="900"/>
<use xlink:href="#entry" x="930" y="835"/>
<use xlink:href="#entry" x="940" y="950"/>
<use xlink:href="#entry" x="970" y="900"/>
<use xlink:href="#entry" x="1000" y="835"/>
<use xlink:href="#entry" x="1010" y="950"/>
#!/usr/bin/env python
import glob, trace, unittest, os, sys
import glob, unittest, os, sys
# start in a consistent, predictable location
# python 2.2 accomodations
from trace import fullmodname
def fullmodname(path):
return os.path.splitext(path)[0].replace(os.sep, '.')
# more python 2.2 accomodations
if not hasattr(unittest.TestCase, 'assertTrue'):
unittest.TestCase.assertTrue = unittest.TestCase.assert_
if not hasattr(unittest.TestCase, 'assertFalse'):
unittest.TestCase.assertFalse = unittest.TestCase.failIf
# try to start in a consistent, predictable location
if sys.path[0]: os.chdir(sys.path[0])
sys.path[0] = os.getcwd()
# find all of the planet test modules
modules = map(trace.fullmodname, glob.glob(os.path.join('tests', 'test_*.py')))
modules = map(fullmodname, glob.glob(os.path.join('tests', 'test_*.py')))
# load all of the tests into a suite
suite = unittest.TestLoader().loadTestsFromNames(modules)
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment