Resume - it's what I've done

For better or worse here are some samples of code I've written to share with the community and give you, my casual visitor, a look at some of the code I hack together from day to day.

I'll eventually get all this into some sort of tagged, searchable system... But I don't have that much right now any way.

Django Admin Auto Register

I'll just be honest- I get tired of writing the same thing over and over in every admin.py so I wrote this to automagically register every class in my models. I find that 9 out of 10 times I want to ignore less than I want to register so this uses "negative trapping" where you specify what you want to skip. It also supports admin classes by matching the model class with the associated admin class in the MODEL_ADMINS dictionary. Makes me smile every time I roll out a new app.

                    
from django.contrib import admin
from my_awesome_app import models

# models that shouldn't be registered
# list of model names as lowered strings
# ['mymodel', 'myothermodel']
EXCLUDE_MODELS = []
# models that have admin classes
# dict of model name strings as keys, admin classes as values
# {'MyModel':MyModelAdmin}
MODEL_ADMINS = {}
for attr in dir(models):
    skip = False
    for model_name in EXCLUDE_MODELS:
        if model_name.lower() in attr.lower():
            skip = True
    if skip: continue
    model_attr = getattr(models, attr)
    if type(model_attr) is type(models.models.Model):
        if attr in MODEL_ADMINS:
            admin.site.register(model_attr, MODEL_ADMINS[attr])
        else:
            try:
                admin.site.register(model_attr)
            except:
                continue   
                    
                

IP Address Range Search

The need arose to be able to see if an IP address belonged in one of several various blocks. These blocks had several available ranges so I wrote this script to search a dictionary of IP address range definitions.

                    
# ip_ranges is a dictionary (keyed off the first octet as an integer) that contains
# a three-tuple of single octet values or two-tuple octet value ranges.
# The dictionary below represents the following ranges:
# 68.24.0.1 - 68.27.255.254
# 68.29.0.1 - 68.29.255.254
# 68.30.0.1 - 68.31.255.254
# 68.240.0.1 - 68.247.255.254
ip_ranges = {
    68:[
        (
            (24,27),(0,255),(1,254),
        ),
        (
            29,(0,255),(1,254),
        ),
        (
            (30,31),(0,255),(1,254),
        ),
        (
            (240,247),(0,255),(1,254),
        ),
        ]
}

def split_ip(ip):
    """
    Returns a list comprehension of ip address octet values as integers.
    >>> split_ip('10.0.0.1')
    ... [10, 0, 0, 1]
    """
    return [int(x) for x in ip.split('.')]
    
def check_range(ranges, ip):
    """
    Loops through an ip range dictionary determining if the given ip is contained
    within the given ranges.
    """
    in_ranges = True
    count = 1
    for r in ranges:
        if in_ranges:
            if type(r) is tuple:
                if ip[count] in range(r[0], r[1]+1):
                    in_ranges = True
                else:
                    in_ranges = False
            else:
                if r == ip[count]:
                    in_ranges = True
                else:
                    in_ranges = False
            count += 1
    return in_ranges

def is_target_ip(ip):
    """
    Determines whether the given ip matches any of our defined ip ranges.
    """
    ip = split_ip(ip)
    if ip_ranges.has_key(ip[0]):
        ranges = ip_ranges[ip[0]]
        for r in ranges:
            if check_range(r, ip):
                return True
    return False  
                    
                

Django Bound Form Field Data

There's not an easy way to get to the data of a bound form field in Django but the community has a solution in the form of a filter. You can read about it at http://code.djangoproject.com/ticket/10427.

As most of those fixes go, at least for me, it didn't solve the problem I had: getting the bound data from a model multiple choice field. My template tags module contains field_tags.py that looks like this...

                    
from django.forms import ChoiceField, FileField, ModelMultipleChoiceField

from django import template
register = template.Library()

@register.filter(name='field_value')
def field_value(field):
	""" 
	Returns the value for this BoundField, as rendered in widgets. 
	""" 
	if field.form.is_bound: 
		if isinstance(field.field, FileField) and field.data is None: 
			val = field.form.initial.get(field.name, field.field.initial) 
		else: 
			val = field.data 
	else:
		val = field.form.initial.get(field.name, field.field.initial)
		if callable(val):
			val = val()
	if val is None:
		val = ''
	return val

@register.filter(name='display_value')
def display_value(field): 
    """
    Returns the displayed value for this BoundField, as rendered in widgets or
    a list of displayed values.
    """
    value = field_value(field)
    if isinstance(field.field, ChoiceField):
        for (val, desc) in field.field.choices:
            if val == value:
                return desc
    if isinstance(field.field, ModelMultipleChoiceField):
        if type(value) is list:
            descs = []
            for val2 in value:
                for (val, desc) in field.field.choices:
                    if val == val2:
                        descs.append(desc)
            if descs:
                return descs
    return value

@register.filter(name='display_value_pairs')
def display_value_pairs(field): 
    """
    Returns the displayed value for this BoundField, as rendered in widgets or
    a list of tuples [("value", "displayed value")]
    """
    value = field_value(field)
    if isinstance(field.field, ModelMultipleChoiceField):
        if type(value) is list:
            ret = []
            for val2 in value:
                for (val, desc) in field.field.choices:
                    if val == val2:
                        ret.append((val2,desc))
            if ret:
                return ret
    return value

                    
                

Matrix Orbital MX 2xx Display Class

I spent the better part of a Saturday figuring out how to talk to my Matrix Orbital LCD with Python. I couldn't find any documentation any where so I did a write up on LCD Forums to help the next lost soul. This hacked class is the result of my day's efforts. On a related note I lost half of a Monday getting this to work on my Mac. I still need to write up how I did that hack before I forget forever...

                    
import os
import re
import serial
import sys
import thread
import time

class Display():
    '''
    Display class for Matrix Orbital MX LCD Screens.
    Essentially a wrapper for serial.Serial with Matrix Orbital functions.
    >>> d = Display(2)
    >>> d.clear()
    >>> d.send("Hello World!")
    '''
    #constants
    ## basic utils
    NULL = '\x00'
    CLEAR = '\xfe\x58'
    CMD = '\xfe'
    BACKLIGHT_ON = '\xfe\x42\x00'
    BACKLIGHT_OFF = '\xfe\x46'
    ## bar graphs
    INIT_VBG_THIN = '\xfe\x73'
    INIT_VBG_THICK = '\xfe\x76'
    INIT_HBG = '\xfe\x68'
    ## input
    KEYS_IN = []
    LISTEN_FOR_KEYS = True

    def clear(self):
        '''Clears the screen'''
        self.send(self.CLEAR)
   
    def __init__(self, port, baud=19200):
        self._serial = serial.Serial(port, baud)
        self.clear()

    def send(self, data):
        '''Wrapper for our serial instance's write method'''
        self._serial.write(data)

    def close(self):
        '''Wrapper for our serial instance's close method'''
        self._serial.close()

    def draw_vbg(self, cols=[], kind="thin"):
        '''Method to draw a vertical bar graph
        cols is an array of two-tuples [(column, height)]
        example usage:
            my_display.draw_vbg([(1,2),(2,4),(3,6)])
        The example would draw a bar graph with bars on
        columns 1, 2, & 3 with heights 2, 4, & 6 (respectively)
        '''
        if kind == "thin":
            self.send(self.INIT_VBG_THIN)
        else:
            self.send(self.INIT_VBG_THICK)

        for col in cols:
            c = int(col[0]) # column to draw
            h = int(col[1]) # height of bar (0-14?)
            try:
                self.send(self.CMD+'\x3d'+chr(c)+chr(h))
            except:
                raise

    def clear_keys(self):
        '''Clears out the KEYS_IN array'''
        self.KEYS_IN = []

    # should not be called outside of class! use key_listen()
    def _thread_key_listen(self):
        while self.LISTEN_FOR_KEYS:
            key = self._serial.read()
            self.KEYS_IN.append(key)
        #clean up on fail or exit
        self.key_listen_thread = None
 
    def key_listen(self):
        '''starts a new thread to listen for key presses and
        inserts them into the KEYS_IN array'''
        self.key_listen_thread = thread.start_new_thread(self._thread_key_listen, ())
                    
                

TimeSpace Tag Filter

TimeSpace has some very complicated filtering that takes place in the back end. What makes it complicated is the simplicity we try to give the user when creating a filter.

When I originally designed the filter system there were different types of filters to accomplish specific tasks. After we started working on the front end we realized that was too confusing so I hacked the "Tag Filter" to provide the needed functionality.

Here's the rub: We had a generic model to represent all the different filters. This was accomplished my having a text field that contained configuration parameters as JSON. This worked well since the UI was done with AJAX and we could toss the JSON config out and the JS on the page could draw out whatever was needed and display the associated values. When the form was saved the additional properties (display and value) were just baked back in as JSON.

With that basic explanation out of the way, the code below extrapolates the additional options and creates a Django Q object from the properties of the filter instance.

                    
# # # # # # # # # #
# filters/tag.py
# Tag filter
#
# Filters MUST be imported into filters/__init__.py
# 
# # # # # # # # # #

import re

from django.db.models import Q
from django import forms

from timespace.forms import BaseFilterForm
from timespace.options import IPTC_KEY_TYPES, FILTER_TYPES, IPTC_TYPE_KEYS
from timespace.utils.json import *



# the module must contain a class of the same name,
# sentence cased (first letter capitolized)
class Tag():
    object = None
    terms = None
    term = None
    operator = None
    params = None
    
    
    def __init__(self, filter=None):
        self.object = filter
        if filter is not None:
            self.terms = self.split_terms(filter.term.lower())
            self.term = filter.term.lower()
            self.operator = filter.operator
            self.parse_params()
        
    def __str__(self):
        return self.__unicode__()
    
    def __unicode__(self):
        return '%s - %s' % (str(self.operator), str(self.term))
    
    # The get Q method.  This returns the filters query
    def get_q(self):
        """Get Q
        
        Returns a django Q object based on the filter operator and terms.
        """
        q = None
        if '*' in self.terms:
            q = '*'
            
        if self.params is not None and q != '*':
            params = self.params
            # sanity check
            if q is None:
                q = Q()
            
            # establish each sections q object as none
            descq = None
            titleq = None
            tagsq = None
            iptcq = None
            # set the filter type
            if params.has_key('exact_match') and params['exact_match']:
                filter_type = '__iexact'
            else:
                filter_type = '__icontains'
            # create the title q object
            if params.has_key('search_title') and params['search_title']:
                for term in self.terms:
                    tq = Q(('title%s'%filter_type,term))
                    if titleq is None:
                        titleq = tq if self.operator is not 'not' else ~tq
                    else:
                        if self.operator == 'can':
                            titleq = titleq | tq
                        if self.operator == 'must':
                            titleq = titleq & tq
                        if self.operator == 'not':
                            titleq = titleq & ~tq
                if titleq is not None:
                    if self.operator == 'can':
                        q = q | titleq
                    if self.operator == 'must':
                        q = q & titleq
                    if self.operator == 'not':
                        q = q & ~titleq
            # create the description q object
            if params.has_key('search_description') and params['search_description']:
                for term in self.terms:
                    tq = Q(('description%s'%filter_type,term))
                    if descq is None:
                        descq = tq if self.operator is not 'not' else ~tq
                    else:
                        if self.operator == 'can':
                            descq = descq | tq
                        if self.operator == 'must':
                            descq = descq & tq
                        if self.operator == 'not':
                            descq = descq & ~tq
                if descq is not None:
                    if self.operator == 'can':
                        q = q | descq
                    if self.operator == 'must':
                        q = q & descq
                    if self.operator == 'not':
                        q = q & ~descq
            # create the tags q object
            if params.has_key('search_tags') and params['search_tags']:
                for term in self.terms:
                    tq = Q(('description%s'%filter_type,term))
                    if tagsq is None:
                        tagsq = tq if self.operator is not 'not' else ~tq
                    else:
                        if self.operator == 'can':
                            tagsq = tagsq | tq
                        if self.operator == 'must':
                            tagsq = tagsq & tq
                        if self.operator == 'not':
                            tagsq = tagsq & ~tq
                if tagsq is not None:
                    if self.operator == 'can':
                        q = q | tagsq
                    if self.operator == 'must':
                        q = q & tagsq
                    if self.operator == 'not':
                        q = q & ~tagsq
            # create the iptc q object
            fields = params['iptc_search_fields']
            if fields and params.has_key('search_iptc') and params['search_iptc']:
                for term in self.terms:
                    for field in fields:
                        field = IPTC_KEY_TYPES[int(field)]
                        # field Q
                        fq = Q(('iptc_info__type__iexact',field))
                        # term Q
                        tq = Q(('iptc_info__value%s'%filter_type,term))
                        # pair Q
                        pq = Q(tq & fq)
                        if self.operator == 'can':
                            if iptcq is None:
                                iptcq = pq
                            else:
                                iptcq = iptcq | pq
                        if self.operator == 'must':
                            if iptcq is None:
                                iptcq = pq
                            else:
                                iptcq = iptcq & pq
                        if self.operator == 'not':
                            if iptcq is None:
                                iptcq = ~pq
                            else:
                                iptcq = iptcq & ~pq
                if iptcq is not None:
                    if self.operator == 'can':
                        q = q | iptcq
                    if self.operator == 'must':
                        q = q & iptcq
                    if self.operator == 'not':
                        q = q & ~iptcq
        return q
    
    # form fields for the form defined below
    # {field_name:"default value"}
    form_fields = {
        "exact_match":False,
        "search_title":True,
        "search_description":True,
        "search_tags":True,
        "search_iptc":False,
        "iptc_search_fields":[],
    }
    
    def get_form(self):
        # changes here need to be updated in self.form_fields
        class FilterForm(BaseFilterForm):
            exact_match = forms.BooleanField(initial=False, required=False)
            search_title = forms.BooleanField(initial=True, required=False)
            search_description = forms.BooleanField(initial=True, required=False)
            search_tags = forms.BooleanField(initial=True, required=False)
            search_iptc = forms.BooleanField(initial=False, required=False)
            iptc_choices = [(x[0],x[1].title()) for x in IPTC_KEY_TYPES.items()]
            iptc_search_fields = forms.CharField(max_length=255, widget=forms.widgets.SelectMultiple(choices=iptc_choices), required=False)
            type = forms.CharField(max_length=100, widget=forms.HiddenInput(), initial='tag')
        return FilterForm
        
    def filter(self, data):
        """Filter method
        
        Searches the given data (string) for a match for the filter instance's
        terms. Will return False if a match is found and the operator is "not"
        
        Returns boolean
        
        """
        for term in self.terms:
            data = data.lower()
            if term in data:
                if self.operator != 'not':
                    return True
                else:
                    return False
            elif term == '*':
                if self.operator != 'not':
                    return True
                else:
                    return False
        if self.operator != 'not':
            return False
        else:
            return True
    
    
    def filter_objects(self, objects, search_field='description'):
        """Object list filtration
        
        Iterates through a list of objects inspecting the specified search_field
        and determing whether the object matches the filters or not.
        
        Returns a list of matching objects
        
        filter_objects([], "the_data_field_to_search")
        """
        results = []
        for o in objects:
            data = getattr(o, search_field, None)
            if data is not None:
                for term in self.terms:
                    if self.filter(data):
                        if o not in results:
                            results.append(o)
        return results
    
    def parse_params(self):
        o = self.object
        if o is not None:
            if o.params is not None and o.params != '':
                params_as_string = o.params
                params = utils_json_load(params_as_string)
                self.params = params
            else:
                self.params = self.form_fields
    
    def split_terms(self, term):
        terms = []
        p = re.compile(r'"(.*?)"')
        groups = p.findall(term)
        terms.extend(groups)
        for t in terms:
            term = term.replace(t,'')
        term = term.replace('""', '')
        unclean_list = [x.strip() for x in term.split(' ')]
        for x in unclean_list:
            if x != '':
                terms.append(x)
        return terms
    
    def load_params(self, filter=None, data=None, form=None):
        """Filter Parser - params load
        Loads json into filter.params from filter instance
        >>> filter.load_params(myFilterModelInstance, {"iptc_only":True})
        """
        json = {}
        if filter is None:
            filter = self.object
        if form is not None:
            data = form.cleaned_data
        if data is not None:
            # confirm that at least 1 field is in the data, if not, this should
            # probably be set to defaults
            set_defaults = True
            for field in self.form_fields.keys():
                if data.has_key(field):
                    set_defaults = False
            if not set_defaults:
                for field, default in self.form_fields.items():
                    if data.has_key(field):
                        value = data[field]
                        # set checkboxes back to boolean values
                        json.update({field:value if value != 'on' else True})
                    # unchecked options don't come in the post data so if a field
                    # is missing and it's a bool then it should be false
                    elif type(default) is bool:
                        json.update({field:False})
            else:
                for field, default in self.form_fields.items():
                    json.update({field:default})
        else:
            data = self.form_fields
        try:
            json = utils_json_dump(json)
            filter.params = json
        except:
            pass
        return json
    
    def dump_params(self, filter=None, alter_instance=False):
        """Filter Parser - params dump        
        BASIC TAG PARAM
        {
            'iptc_only':True
            'iptc_fields':['subcategory', 'title']
        }
        """
        json = {}
        if filter is None:
            filter = self.object
        try:
            if filter.params is not None and filter.params != '':
                json = utils_json_load(filter.params)
            else:
                json = self.form_fields
        except:
            pass
        return json