Code Snippets
A scons SContruct file and rake Rakefile that do the same thing
I've been trying to figure out how to use Rake - and how to use Scons. Scons has been around a while and seems further along in some ways. At the same time, for someone that doesn't know anything (me) it's hard to even figure out how to copy files. There has to be a better way, but this is what I came up with
In Ant this would be easy, and I could be more recursive about it
<copy dir="${build.dir}" includes="**/.*py, **/.*kid, **/*.xsl"/>
or something to that effect. So for now Ant seems easier.
# THE RAKE FILE
directory "deploy/bin"
directory "deploy/pyscripts/whs"
directory "deploy/pyscripts/whs/stylesheet"
directory "deploy/pyscripts/whs/templates"
task :default => [:deploy]
file "publish.pyw" => ["publish.py"] do |f|
cp "publish.py", f.name
end
task :publish => 'publish.pyw'
task :deploy => [:publish, "deploy/bin", "deploy/pyscripts/whs",
"deploy/pyscripts/whs/stylesheet",
"deploy/pyscripts/whs/templates"]
file "deploy/bin" do |f|
cp Dir["**.pyw"], f.name
end
file "deploy/pyscripts/whs" do |f|
cp Dir["whs/**.py"], f.name
end
file "deploy/pyscripts/whs/stylesheet" do |f|
cp Dir["whs/stylesheet/**.xsl"], f.name
end
file "deploy/pyscripts/whs/templates" do |f|
cp Dir["whs/templates/**.kid"], f.name
end
#END RAKE
# THE SCONS FILE
import glob
import os
environment = Environment(ENV = {'PATH' : os.environ['PATH']})
make_windows_file = environment.InstallAs('publish.pyw',
File('publish.py'))
copy_main = environment.Install(dir=Dir('deploy/bin'),
source=glob.glob("*.py[w]"))
copy_module = environment.Install(dir=Dir('deploy/pyscripts/whs'),
source=glob.glob("whs/*.py"))
copy_templates = environment.Install(dir=Dir('deploy/pyscripts/whs/templates'),
source=glob.glob("whs/templates/*.kid"))
copy_xsl = environment.Install(dir=Dir('deploy/pyscripts/whs/stylesheet'),
source=glob.glob("whs/stylesheet/*.xsl"))
Alias("make_windows_file", make_windows_file)
Alias("main", copy_main)
Alias("module", copy_module)
Alias("templates", copy_templates)
Alias("xsl", copy_xsl)
Default("make_windows_file", "main","module","templates","xsl")
# END SCONS
03/30/06
ServletFilter that creates a chain of XMLFilter(s)
a class that extends ServletFilter that can make a chain of XMLFilter objects apply to the output. The basic idea is that you can infinitely add SAX Filters to the Xml before it is output. I had a need to do this for a while with something resembling a rules engine. The idea was to store all information about fields in a seperate configuration - such as required, length etc... and use that information to effect the html output
package org.klangworks;
import java.util.Iterator;
import java.util.List;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.ListIterator;
import java.util.Enumeration;
import java.util.StringTokenizer;
import java.io.CharArrayWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringReader;
import org.xml.sax.XMLReader;
import org.xml.sax.XMLFilter;
import org.xml.sax.SAXNotRecognizedException;
import org.xml.sax.SAXNotSupportedException;
import org.xml.sax.DTDHandler;
import org.xml.sax.EntityResolver;
import org.xml.sax.ErrorHandler;
import org.xml.sax.ContentHandler;
import org.xml.sax.SAXException;
import org.xml.sax.InputSource;
import org.xml.sax.Attributes;
import org.xml.sax.helpers.DefaultHandler;
import org.xml.sax.helpers.AttributesImpl;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import org.apache.log4j.Logger;
import javax.xml.parsers.SAXParserFactory;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.sax.SAXTransformerFactory;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.sax.SAXSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.TransformerException;
import org.xml.sax.helpers.XMLFilterImpl;
/**
* Servlet Filter to apply XMLFilters to the content
* before it is sent to the browser
*
*@author rob nelson
*@created August 4, 2005
*/
public class XMLServletFilter implements Filter {
private FilterConfig filterConfig = null;
private SAXParser parser;
private XMLReader reader;
private Transformer transformer;
private String contentType;
private String filterStr;
private List filters;
private XMLFilter theFilter;
/**
* Log4j Logger
*/
public static Logger logger =
Logger.getLogger("net.klangworks.XMLServletFilter");
/**
* Initialization routine. Reads parameters from web.xml
* sets up the parsers and reads in and creates all the
* XMLFilter[] filters
*
*@param filterConfig The web.xml configuration info
*@exception ServletException Exception on the servlet
*/
public void init(FilterConfig filterConfig) throws ServletException {
this.filterConfig = filterConfig;
filterStr = filterConfig.getInitParameter("filters");
contentType = filterConfig.getInitParameter("content-type");
filters = new ArrayList();
try {
StringTokenizer st = new StringTokenizer(filterStr, ",");
while (st.hasMoreTokens()) {
Class clazz = Class.forName(st.nextToken());
XMLFilter filter = (XMLFilter) clazz.newInstance();
filters.add(filter);
}
SAXParserFactory spf = SAXParserFactory.newInstance();
spf.setNamespaceAware(true);
parser = spf.newSAXParser();
reader = parser.getXMLReader();
SAXTransformerFactory stf =
(SAXTransformerFactory) TransformerFactory.newInstance();
transformer = stf.newTransformer();
transformer.setOutputProperty(
javax.xml.transform.OutputKeys.OMIT_XML_DECLARATION,
"yes");
XMLFilter[] filterArray = (XMLFilter[]) filters.toArray(new XMLFilter[0]);
filterArray[0].setParent(reader);
int size = filterArray.length;
int flag = 1;
while (flag < size) {
filterArray[1].setParent(filterArray[flag - 1]);
flag++;
}
theFilter = filterArray[size - 1];
} catch (Exception e) {
throw new ServletException(e);
}
}
/**
* What to do when the filter is applied. The will be called
* for every page it is applied ot
*
*@param request HttpRequest
*@param response HttpResponse
*@param chain The existing chain of filters
*@exception IOException an exception with I/O
*@exception ServletException a servlet wide exception
*/
public void doFilter(
ServletRequest request,
ServletResponse response,
FilterChain chain)
throws IOException, ServletException {
response.setContentType(contentType);
CharResponseWrapper wrapper =
new CharResponseWrapper((HttpServletResponse) response);
chain.doFilter(request, wrapper);
logger.debug("trying to run XMLServletFilter");
try {
InputSource source =
new InputSource(new StringReader(wrapper.toString()));
SAXSource saxSource = new SAXSource(theFilter, source);
StreamResult result = new StreamResult(response.getWriter());
transformer.transform(saxSource, result);
} catch (TransformerException tfe) {
throw new ServletException(tfe);
}
}
/**
* What happens when the Filter is removed
*/
public void destroy() {
this.filterConfig = null;
}
}
It requires this simple class:
package org.klangworks;
import java.io.CharArrayWriter;
import java.io.PrintWriter;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
/**
* A Wrapper around a Servlet Response so we can intercept it and write
* something else
*
*@author robnelson
*@created August 2, 2005
*/
public class CharResponseWrapper extends HttpServletResponseWrapper {
private CharArrayWriter output;
/**
* Get the output as a String
*
*@return A string representation of the output
*/
public String toString() {
return output.toString();
}
/**
* Constructor
*
*@param response The response to wrap
*/
public CharResponseWrapper(HttpServletResponse response) {
super(response);
output = new CharArrayWriter();
}
/**
* Gets the writer attribute of the CharResponseWrapper object
*
*@return The writer value
*/
public PrintWriter getWriter() {
return new PrintWriter(output);
}
}
04/28/06
Add leading zeros to a number
This is kind of stupid, but it took a while to find this. The number (3) determines the number of digits total
number = 5
new_number = "%(#)03d" % {"#": number}
returns 005
05/08/06
Getting the current directory
I lost this the other day, and found it difficult to find on the internet. It's stupid simple, but I never quite remember
from os import path MODULE_HOME = path.dirname(path.abspath(__file__))
05/08/06
Calling Django from Scons
Note I've updated this recently. It only works using Django > 0.95
# UPDATE - this has gotten easier as of Django 0.95 (Magic Removal)
from django.conf import settings as django_settings
MODULE_HOME = path.dirname('.')
template_dirs = (
path.join(MODULE_HOME, 'templates'),
)
django_settings.configure(DEBUG=True,
TEMPLATE_DEBUG=True,
TEMPLATE_DIRS=template_dirs,
)
from django.template import Context, Template
from django.template import loader
""" run django templates"""
def run_django(target, source, env):
""" runs a django template, given target and source and dict of values"""
input_file = str(source[0]).encode('utf-8')
output_file = str(target[0]).encode('utf-8')
t = Template(open(input_file).read())
# FIXME: could use this
#django.template.loader.get_template(template_name)
c = Context(env['context'])
outfile = file(output_file, 'w')
outfile.write(t.render(c))
outfile.close()
return None
django = Builder(action = run_django, suffix='.html', src_suffix='.html')
env = Environment(ENV = {'PATH' : os.environ['PATH']},
BUILDERS = {'Django' : django}
)
index_context = {"current_page": "default"}
index = env.Django(source="templates/default.html",target="site/default.html",context=index_context)
env.Alias("index", index)
env.Default("index")
09/13/06
Keeping a log of updates to records in Django
I had the task of creating an RSS feed for wiki items as they are updated. I figured I would just use Django's post_save method. But then there was the classic chicken/egg problem. Luckily Django has the undocumented replaces_module meta attribute.
2/14/2007: I've changed this recently. After the "magic-removal" branch - this was much easier. So this only works for Django >= 0.95 and the replaces_module is no longer used. In fact that makes this bit of code trivial and typical, but I'm leaving it here anyway
from django.db import models
import datetime
class Tag(models.Model):
"""Tag (subject) of a Wikipage"""
name = models.SlugField(maxlength=75)
class Admin:
pass
class Meta:
db_table = "wiki_tags"
def __str__(self):
return self.name
class Wikihistory(models.Model):
"""Wiki History for RSS"""
wikipage = models.ForeignKey("Wikipage",db_column="wiki_page_id")
created_at = models.DateTimeField(auto_now_add=True)
class Admin:
pass
class Meta:
db_table = "wiki_history"
def __str__(self):
if self.wikipage:
return self.wikipage.title + " " + self.created_at.strftime("%m/%d/%y %I:%M %p")
else:
return self.created_at
def get_absolute_url(self):
date_formatted = self.created_at.strftime("%Y%m%d:%I:%M:%p")
if self.wikipage:
return "/wiki/view/%s" % (self.wikipage.title)
else:
return ""
class Wikipage(models.Model):
"""Wiki page"""
title = models.CharField(maxlength=75)
content = models.TextField(null=True,blank=True)
tags = models.ManyToManyField(Tag,null=True,blank=True)
class Admin:
pass
class Meta:
db_table = "wiki_wikipages"
def first_letter(self):
return self.title[0].upper()
def __str__(self):
return self.title
def save(self):
super(Wikipage, self).save()
entry = Wikihistory(wikipage=self)
entry.save()
def get_absolute_url(self):
return "/wiki/%s/" % self.title
02/14/07