"""
Handling page requests
"""
# for filesystem ops
import os, os.path
# for ResponseError
import http
# for TemplatePage
import template
# path to directory containing the page heirarcy
PAGE_DIR = "pages"
# path to directory containing the list of visible pages
PAGE_LIST_FILE = os.path.join(PAGE_DIR, "list")
class PageError (http.ResponseError) :
"""
Error looking up/handling a page
"""
pass
class PageList (object) :
"""
The list of pages
"""
def __init__ (self) :
"""
Loads the page list from the list file
"""
# initialize list of pages
self.pages = []
# load from file
self._load(PAGE_LIST_FILE)
def _load (self, path) :
"""
Processes the lines in the given file
"""
for line in open(path, 'rb') :
# ignore whitespace
line = line.strip()
# ignore empty lines
if not line :
continue
# parse line
url, title = line.split(':')
# add
self._add_item(url.strip(), title.strip())
def _add_item (self, url, title) :
"""
Add item to pages list
"""
self.pages.append((url, title))
def get_title (self, page) :
"""
Gets the title for the given page, or None if not found
"""
return dict(self.pages).get(page)
def get_siblings (self, page) :
"""
Gets the (url, title) tuple list of siblings (including the given page itself) for the given page
"""
siblings = []
# parent url
parent = os.path.split(page.url)[0]
# how many segments in the page name
segment_count = len(page.url.split('/'))
# go through all pages
for url, title in self.pages :
# it's a sibling if the parent is the same, and the number of segments it the same
if url.startswith(parent) and len(url.split('/')) == segment_count :
siblings.append((url, title))
# return
return siblings
# global singleton instance
page_list = PageList()
class Page (object) :
"""
This object represents the information about our attempt to render some specific page
"""
def __init__ (self, url, path, basename, url_tail) :
"""
Initialize the page at the given location
@param url the URL leading to this page
@param path the filesystem path to this page's file
@param basename the filesystem name of this page's file, without the file extension
@param url_trail trailing URL for this page
"""
# store
self.url = url
self.path = path
self.basename = basename
self.url_tail = url_tail
# sub-init
self._init()
def _init (self) :
"""
Do initial data loading, etc
"""
pass
@property
def title (self) :
"""
Return the page's title
Defaults to the retreiving the page title from page_list, or basename in Titlecase.
"""
# lookup in page_list
title = page_list.get_title(self.url)
# fallback to titlecase
if not title :
title = self.basename.title()
return title
@property
def content (self) :
"""
Return the page content as a string
"""
abstract
class HTMLPage (Page) :
"""
A simple .html page that's just passed through directly
"""
@property
def content (self) :
"""
Opens the .html file, reads and returns contents
"""
return open(self.path, 'rb').read()
class TemplatePage (Page) :
"""
A template that's rendered using our template library
"""
@property
def content (self) :
"""
Loads the .tmpl file, and renders it
"""
return template.render_file(self.path)
# list of page handlers, by type
TYPE_HANDLERS = [
('html', HTMLPage ),
(template.TEMPLATE_EXT, TemplatePage ),
]
def _lookup_handler (url, path, filename, basename, extension, tail) :
"""
We found the file that we looked for, now get its handler
"""
# find appropriate handler
for handler_ext, handler in TYPE_HANDLERS :
# match against file extension?
if handler_ext == extension :
# found handler, return instance
return handler(url, path, basename, tail)
# no handler found
raise PageError("No handler found for page %r of type %r" % (url, extension))
def lookup (name) :
"""
Look up and return a Page object for the given page, or raise an error
"""
# inital path
path = PAGE_DIR
url_segments = []
# name segments
segments = name.split('/')
# iterate through the parts of the page segments
while segments :
# pop segment
segment = segments.pop(0)
# add to page url
url_segments.append(segment)
# translate empty -> index
if not segment :
segment = 'index'
# look for it in the dir
for filename in os.listdir(path) :
# build full file path
file_path = os.path.join(path, filename)
# stat, recurse into subdirectory?
if os.path.isdir(file_path) and filename == segment :
# use new dir
path = file_path
# break for-loop to look at next segment
break
# split into basename + extension
basename, extension = os.path.splitext(filename)
# ...remove that dot
extension = extension.lstrip('.')
# match against requested page name?
if basename == segment :
# found the file we wanted
return _lookup_handler('/'.join(url_segments), file_path, filename, basename, extension, '/'.join(segments))
else :
# inspect next file in dir
continue
# did not find the filename we were looking for in os.listdir
raise PageError("Page not found: %s" % name, status='404 Not Found')