Restarting Apache with Python

It doesn't happen a lot but when it does it is frustrating. Since the server that runs this site is modest in every means I sometimes will check out how things are going and find out that the Apache2 web server has stopped running on the server. The last time this happened I did a quick search to see what others were doing to manage the problem. There were a few packages that will monitor the server for you and then restart it if needed but every one of them took a lot more work to manage and install than I really wanted to do. So I wrote a quick Python script that combined with cron do the job very nicely.

#!/usr/bin/env python

from os import system, path

pidFile = '/var/run/apache2.pid'
startCmd = 'apache2 -k start'

if not path.exists(pidFile):
    system(startCmd)

The basic idea is that most *nix services use a pid file to store the ID number of the process that was assigned to the service when the service was started. If the service is running then there will be a pid file for that service and no pid file if the service is not running.

To start out, test to see whether the pid file exists. It is located at /var/run/apache2.pid on my server. Your setup may vary so check your setup before proceeding. I also created a symlink to /usr/bin for Apache at /usr/bin/apache2 -> /etc/init.d/apache2 which allows me to type just 'Apache2' at the prompt instead of the entire path to Apache. If the pid file does not exist that means Apache isn't running so go ahead and send a start command to the server via 'apache2 –k start'

I saved this code as a file in my home directory and created a cron job to run the file once each minute.

Modulo In Django Templates

Ever find yourself wishing for the modulo operator (%) in Django templates? I did. Its easy enough to create your own custom filter so why not do it?

Caveat: I couldn't figure out how to get the filter to accept two arguments to do the modulo test against so I defaulted the test value to zero. If there is a way to add a second argument I would love to add that to the code.

In the templatetags directory of your Django install, add a file named 'mod.py'. In that file add the following code:

from django import template
register = template.Library()

def mod(value, arg):
    if value % arg == 0:
        return True
    else:
        return False

register.filter('mod', mod)

In your template use the mod filter like this:

...
{% load mod %}
...
<tr bgcolor="{% if forloop.counter|mod:2 %}#cccccc{% else %}#ffffff">
...

This will alternate every other row's background color between gray and white.

DateFormat with Python

My early background in programming is in ColdFusion. Since I found python I do not really use ColdFusion for much any more but it is still one of my favorite languages. One of the features I missed most about ColdFusion is the DateFormat() built-in function. Python's default date formatting syntax is arcane in my opinion and very difficult to remember at best. I always find myself going back to the documentation to figure it out. Worry no more. Introducing ... DateFormat() for python based on the ColdFusion DateFormat() function. It is not a terribly unique name by any means but it takes all the guess work out of remembering how to format a date by using a string mask to show how you want the date to appear. The following values can be used in the mask:

  • d: Day of the month as digits; no leading zero for single-digit days.
  • dd: Day of the month as digits; leading zero for single-digit days.
  • ddd: Day of the week as a three-letter abbreviation.
  • dddd: Day of the week as its full name.
  • m: Month as digits; no leading zero for single-digit months.
  • mm: Month as digits; leading zero for single-digit months.
  • mmm: Month as a three-letter abbreviation.
  • mmmm: Month as its full name.
  • yy: Year as last two digits; leading zero for years less than 10.
  • yyyy: Year represented by four digits.

The following masks tell how to format the full date and cannot be combined with other masks:

  • short: equivalent to m/d/yy.
  • medium: equivalent to mmm d, yyyy.
  • long: equivalent to mmmm d, yyyy.
  • full: equivalent to dddd, mmmm d, yyyy.

Example usage is:

>>>import datetime
>>>today = datetime.datetime.today()
>>> DateFormat(today, 'mm-dd-yyyy')
'09-20-2007'
>>>DateFormat(today, 'ddd, mmm d, yyyy')
'Thu, Sep 20, 2007'
>>>DateFormat(today, 'm/d/yy')
'9/20/07'
>>>DateFormat(today, 'full')
'Thursday, September 20, 2007'

Download it here

Unzip Un-needed in Python?

I recently read a post that contends that an unzip function is unneeded in python. His argument is that you don't need unzip because of the following:

>>> t1 = (0,1,2,3)
>>> t2 = (7,6,5,4)
>>> [t1,t2] == zip(*zip(t1,t2))
True

Oh, of course! How intuitive! OK, no more sarcasm. To me that seems to be very un-pythonic. I never would have thought to use *zip() inside of zip() to get the unzipped version. I would however have expected to be able to write unzip() and get a result. I decided to see how easy it would be to create an unzip() of my own so I fired this off just to see.

def unzip(l):
    if len(l) < 1:
        return []
    
    itemCount = len(l[0])
    
    unzipped = []
    
    for i in range(itemCount):
        unzipped.append(tuple([j[i] for j in l]))
    
    return unzipped

if __name__ == '__main__':
    
    t1 = ("brian","becca","hyrum","david")
    t2 = (29,30,3,27)
    t3 = ("utah","utah","utah","arizona")
    
    zipped = zip(t1,t2,t3)
    unzipped = unzip(zipped)
    
    print zipped
    print unzipped

Starting BlueDragon with Python

I don't know about anybody else but the default startup script that installs with BlueDragon on linux never worked for me. It always failed to do anything. I descended into having to manually restart BlueDragon every time I restarted my server which is a real pain. I know a real sys admin would have solved this long ago. Well the pain goes on no longer. I finally realized that I can use python to start the service for me as system start time. Here is the code.

#!usr/bin/env python

import os

os.system('sh /usr/local/NewAtlanta/BlueDragon_Server_70/bin/StartBlueDragon.sh')

Python - 1 : C# - 0

I tend to get chided when I mention to my developer friends that I prefer to work in Python if I can. Python is a general purpose language that helps me get my personal projects done faster with less coding. I'll follow up with a post on things I like and dislike about Python on another post later.

At work we work exclusively on Microsoft SharePoint Server with C#. One of our developers was trying to write a routine that would write 50MB of data from MS SQL Server to Excel. Using C# our guy couldn't get the run time to be under 30 minutes. To me, 50MB isn't a lot of data. There's no reason that it should take that long.

A quick Google search to find a Python module to connect to MS SQL Server turned up PyODBC. With the excellent pyExcelerator library installed I was ready for battle. Fifteen minutes† and thirty lines of code later (including timing code) I had a quick prototype in Python working that runs in 49 seconds. Down from 30 minutes, that's a 3573% speed increase. Needless to say my co-workers were all dumbfounded that Python would be so efficient over Microsoft's flagship language. I admit that I was pleasantly surprised as well but mostly just so that I wouldn't have to eat crow when it didn't work ;)

†The only reason it took fifteen minutes was because I had to familiarize myself with PyODBC and how to execute stored procedures with it. After fetching the data it was only two simple for loops to get the data written.