I've recently re-written a Python script I use to run a couple of lightweight blogs. Looking over the horrible code I'd written before, I decided to rewrite it using object-oriented concepts. I wanted to submit it to get feedback, best practices, and other areas I should look at. This is my first script that uses any object oriented ideas.
import markdown
import jinja2
import re
import datetime
import time
import glob
import cgi
class Article:
def __init__(self, local_dir, local_file):
local_file = local_file.replace('/','')
self.local_file_name = local_file
with open(local_dir + '/' + local_file) as f:
self.lines = f.readlines()
self.file_text = ''.join(self.lines[4:])
def text(self):
return self.file_text
def title(self):
title = self.get_metadata(self.lines[0])
return title
def html_filename(self):
html_filename = re.sub('.txt','.html',self.local_file_name)
return html_filename
def date_text(self):
date_text = self.get_metadata(self.lines[2])
return date_text
def date_datetime(self):
date_txt = self.date_text()
date_obj = datetime.datetime.strptime(date_txt, '%d %B %Y')
return date_obj
def date_rss(self):
date = time.strptime(self.date_text(), '%d %B %Y')
rss_date = time.strftime('%a, %d %b %Y 06:%M:%S +0000', date)
return rss_date
def summary(self):
summary = re.sub('<[^<]+?>','', self.html())[0:200]
summary = re.sub('\n',' ',summary)
return summary
def html(self):
md = markdown.Markdown()
converted_text = md.convert(self.file_text).encode('utf-8')
return converted_text
def get_metadata(self,line):
element = re.sub('\n|Author: |Date: |Title: ','',line)
element = cgi.escape(element).strip()
return element
class FileList:
def __init__(self, dir, ignore_list):
self.textfiles = glob.glob(dir+"/*.txt")
for ignored_file in ignore_list:
self.textfiles.remove(dir+ignored_file)
def files(self):
return self.textfiles
class Site:
def load_articles(self, dir, ignore_list):
file_list = FileList(dir, ignore_list)
articles = []
for file in file_list.files():
article = Article(dir, file.replace(dir,''))
articles.append({
'title': article.title(),
'datetime': article.date_datetime(),
'text': article.text(),
'summary': article.summary(),
'html': article.html(),
'date_text': article.date_text(),
'html_filename': article.html_filename(),
'date_rss': article.date_rss()
},)
articles = sorted(articles, key=lambda k: k['datetime'], reverse=True)
return articles
def build_from_template(self, data, template, output_file, dir):
with open(template) as f:
template = jinja2.Template(f.read())
with open(dir + '/' + output_file,'w') as i:
i.write(template.render(data = data))
return True
def build_site(self, params):
dir = params['DIR']
template_dir = params['TEMPLATE_DIR']
index_template = template_dir + '/index_template.html'
archive_template = template_dir + '/archive_template.html'
rss_template = template_dir + '/rss_template.xml'
article_template = template_dir + '/article_template.html'
index_output = '/index.html'
archive_output = '/archive.html'
rss_output = '/index.xml'
site = Site()
articles = site.load_articles(dir, params['IGNORE_LIST'])
for article in articles:
output = article['html_filename']
site.build_from_template(article, article_template, output, dir)
site.build_from_template(articles, index_template, index_output, dir)
site.build_from_template(articles, archive_template, archive_output, dir)
site.build_from_template(articles, rss_template, rss_output, dir)
return True
Here's the script that executes the code above to actually build a site:
#!/usr/local/bin/python
import pueblo
PARAMS = {
'DIR': '/dir/to/your/html/files/', # no final slash
'TEMPLATE_DIR': '/dir/to/store/your/templates', # no final slash
'IGNORE_LIST': ['ignorethis.txt']
}
print "Content-type: text/html\n\n"
site = pueblo.Site()
site.build_site(PARAMS)
print "<html><head><title>Site Rebuilt</title></head><body><h1>Site Rebuilt</h1></body></html>"
and finally, here's an example Jinja2 template:
<!DOCTYPE html>
<title>yoursite.com</title>
<link rel="stylesheet" type="text/css" href="style.css">
<meta name="viewport" content="user-scalable=yes, width=device-width" />
<link href="./index.xml" rel="alternate" type="application/rss+xml" />
<h1>yoursite.com</h1>
<p class="site_description">your description</p>
<ul class="navbar">
<li class="navitem"><a href="your_about_page.html">about</a></li>
<li class="navitem"><a href="./archive.html">archive</a></li>
</ul></div>
<div class="article_list">
{% for i in range(30) %}
<h2><a href="{{ data[i].html_filename }}">{{ data[i].title }}</a></h2>
<p>{{ data[i].date_text }}: {{ data[i].summary }} <a href="{{ data[i].html_filename }}">...</a></p>
{% endfor %}
<h2><a href="archive.html">View All Articles</a></h2>