Klangworks.org


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