<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Nine More Minutes &#187; Python</title>
	<atom:link href="http://www.ninemoreminutes.com/category/programming-languages/python/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.ninemoreminutes.com</link>
	<description>Software Design and Consulting</description>
	<lastBuildDate>Tue, 09 Mar 2010 20:29:55 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Good Morning From PyCon</title>
		<link>http://www.ninemoreminutes.com/2010/02/good-morning-from-pycon/</link>
		<comments>http://www.ninemoreminutes.com/2010/02/good-morning-from-pycon/#comments</comments>
		<pubDate>Fri, 19 Feb 2010 14:54:32 +0000</pubDate>
		<dc:creator>chris</dc:creator>
				<category><![CDATA[Python]]></category>
		<category><![CDATA[pycon]]></category>

		<guid isPermaLink="false">http://www.ninemoreminutes.com/?p=201</guid>
		<description><![CDATA[I have made the journey to the mecca of nerdery, at least my kind of nerds.  Nerds who write Python.  I&#8217;m at PyCon 2010 Atlanta.
The morning begins with Guido&#8217;s keynote, answering questions posted via Twitter: #python.
More to come&#8230;
]]></description>
			<content:encoded><![CDATA[<p>I have made the journey to the mecca of nerdery, at least my kind of nerds.  Nerds who write Python.  I&#8217;m at <a href="http://us.pycon.org/">PyCon 2010 Atlanta</a>.</p>
<p>The morning begins with Guido&#8217;s keynote, answering questions posted via Twitter: <a href="http://twitter.com/#search?q=%23pycon">#python</a>.</p>
<p>More to come&#8230;</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ninemoreminutes.com/2010/02/good-morning-from-pycon/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Google Maps with Python and KML</title>
		<link>http://www.ninemoreminutes.com/2009/12/google-maps-with-python-and-kml/</link>
		<comments>http://www.ninemoreminutes.com/2009/12/google-maps-with-python-and-kml/#comments</comments>
		<pubDate>Fri, 18 Dec 2009 01:02:48 +0000</pubDate>
		<dc:creator>chris</dc:creator>
				<category><![CDATA[Python]]></category>
		<category><![CDATA[TriZPUG]]></category>
		<category><![CDATA[Web]]></category>

		<guid isPermaLink="false">http://www.ninemoreminutes.com/?p=181</guid>
		<description><![CDATA[Here&#8217;s a little guide on how to make a &#8220;custom&#8221; Google Map using Python to generate KML.  It&#8217;s a simple way to display your own placemarks on a Google Map or generate a file that can be imported into Google Earth.  And it uses only modules available in the Python standard library, so there are [...]]]></description>
			<content:encoded><![CDATA[<p>Here&#8217;s a little guide on how to make a &#8220;custom&#8221; Google Map using Python to generate KML.  It&#8217;s a simple way to display your own placemarks on a Google Map or generate a file that can be imported into Google Earth.  And it uses only modules available in the Python standard library, so there are no additional dependencies other than Python itself.<span id="more-181"></span></p>
<h3>Importing Addresses</h3>
<p>I started this project with an Excel spreadsheet someone had sent me, and of course immediately saved it to CSV so I could read in from Python.  I&#8217;ve changed the names and addresses below to protect the innocent, indemnify the guilty, and remove any traces linking me to the incident.  Instead, I&#8217;ll just list my favorite places to find sweet tea along with delicious chicken and biscuits.</p>
<pre style="background: #e0e0e0; color: #000040; overflow: scroll;">name,address,city,state,zip,phone,county
Apex - Williams Street,1581 East Williams Street,Apex,NC,27539,919-362-6796,Wake
Apex - Laura Village Drive,1209 Laura Village Drive,Apex,NC,27502,919-362-1416,Wake
Durham - Garrett Road,4600 Garrett Road,Durham,NC,27701,919-489-5942,Durham
Durham - Guess Road,2801 Guess Road,Durham,NC,27705,919-477-2362,Durham
Durham - Hillsboro Road,3558 Hillsboro Road,Durham,NC,27705,919-383-6797,Durham
Durham - Miami Boulevard,1712 Miami Boulevard,Durham,NC,27703,919-596-4330,Durham
Durham - South Miami Boulevard,5425 South Miami Boulevard,Durham,NC,27703,919-941-5620,Durham
Durham - Roxboro Road,4521 Roxboro Road,Durham,NC,27702,919-471-0581,
Fuquay Varina,1400 N. Main Street,Fuquay Varina,NC,27526,919-557-0749,Wake
Garner - Jones Sausage Road,3920 Jones Sausage Road,Garner,NC,27529,919-662-1621,Wake
Garner - NC 42 East,5497 NC 42 East,Garner,NC,27529,919-773-9116,Wake
...</pre>
<p>Using the <a href="http://docs.python.org/library/csv.html">csv</a> module in the Python standard library, it&#8217;s a piece of <span style="text-decoration: line-through;">fried chicken</span> cake to read in the CSV and return a dictionary for each row.  In my situation, I had a spreadsheet with some missing values, so I filtered the rows to only include the ones with complete addresses.</p>
<pre style="background: #e0e0e0; color: #000040; overflow: scroll;">import csv

def read_addresses(filename):
    """Retrieve addresses from the given CSV filename."""
    required_fields = set(['name', 'address', 'city', 'zip'])
    reader = csv.DictReader(file(filename, 'rU'))
    for row in reader:
        if not all(row.get(f, '').strip() for f in required_fields):
            continue
        yield row</pre>
<p>And then a little code to just use the first argument to the script as the filename.</p>
<pre style="background: #e0e0e0; color: #000040; overflow: scroll;">import sys

if __name__ == '__main__':
    for address in read_addresses(sys.argv[1]):
        print address</pre>
<h3>Geocoding</h3>
<p>Now, we need to use the <a href="http://code.google.com/apis/maps/documentation/geocoding/index.html">Google Maps API</a> to geocode our addresses and return the latitude and longitude in <a href="http://code.google.com/apis/maps/documentation/geocoding/index.html#CSV">CSV</a> format.</p>
<pre style="background: #e0e0e0; color: #000040; overflow: scroll;">import urllib
import urlparse

def geocode(address):
    """Geocode the given address, updating the standardized address, latitude,
    and longitude."""
    qs = dict(q=address['address_string'], key=GMAPS_API_KEY, sensor='true',
              output='csv')
    qs = urllib.urlencode(qs)
    url = urlparse.urlunsplit(('http', 'maps.google.com', '/maps/geo', qs, ''))
    f = urllib.urlopen(url)
    result = list(csv.DictReader(f, ('status', 'accurary', 'latitude', 'longitude')))[0]
    if int(result['status']) != 200:
        raise RuntimeError, 'could not geocode address %s (%s)' % \
                            (address, result['status'])
    address['latitude'] = result['latitude']
    address['longitude'] = result['longitude']</pre>
<p>To iterate over the addresses and format them for geocoding, we use the following code:</p>
<pre style="background: #e0e0e0; color: #000040; overflow: scroll;">for address in read_addresses(sys.argv[1]):
    address['address_string'] = \
            '%(address)s, %(city)s, %(state)s %(zip)s' % address
    geocode(address)</pre>
<h3>Geocoding to Make Google Happy</h3>
<p>The geocoding works, well almost.  It seems to start out fine, then ends up returning quite a few errors as it goes along.  When we look at the <a href="http://code.google.com/apis/maps/documentation/geocoding/index.html#StatusCodes">status code</a> returned, it&#8217;s a 620 &#8211; G_GEO_TOO_MANY_QUERIES.  So we just add a sleep to the geocode function and it makes it through all the addresses, albeit a little more slowly now.</p>
<pre style="background: #e0e0e0; color: #000040; overflow: scroll;">import time

def geocode(address):
    ...
    time.sleep(1.0)</pre>
<h3>Generating KML</h3>
<p>Now than we have addresses with their corresponding coordinates, we can start to create a <a href="http://code.google.com/apis/kml/documentation/">KML</a> document with our placemarks.</p>
<pre style="background: #e0e0e0; color: #000040; overflow: scroll;">import xml.dom.minidom

def create_document(title, description=''):
    """Create the overall KML document."""
    doc = xml.dom.minidom.Document()
    kml = doc.createElement('kml')
    kml.setAttribute('xmlns', 'http://www.opengis.net/kml/2.2')
    doc.appendChild(kml)
    document = doc.createElement('Document')
    kml.appendChild(document)
    docName = doc.createElement('name')
    document.appendChild(docName)
    docName_text = doc.createTextNode(title)
    docName.appendChild(docName_text)
    docDesc = doc.createElement('description')
    document.appendChild(docDesc)
    docDesc_text = doc.createTextNode(description)
    docDesc.appendChild(docDesc_text)
    return doc</pre>
<p>And to use this method to create a basic document, we call it with our title and description parameters.  The second line gets the Document element of the overall KML doc; this is the element to which we&#8217;ll append other child elements.</p>
<pre style="background: #e0e0e0; color: #000040; overflow: scroll;">    kml_doc = create_document('RDU Bojangle\'s',
                              'Sweet Tea, Chicken and Biscuits')
    document = kml_doc.documentElement.getElementsByTagName('Document')[0]</pre>
<p>Now we need a way to create a placemark using the address information we&#8217;ve obtained from geocoding.  We put the phone number in the description, if there is one available.</p>
<pre style="background: #e0e0e0; color: #000040; overflow: scroll;">def create_placemark(address):
    """Generate the KML Placemark for a given address."""
    doc = xml.dom.minidom.Document()
    pm = doc.createElement("Placemark")
    doc.appendChild(pm)
    name = doc.createElement("name")
    pm.appendChild(name)
    name_text = doc.createTextNode('%(name)s' % address)
    name.appendChild(name_text)
    desc = doc.createElement("description")
    pm.appendChild(desc)
    desc_text = doc.createTextNode(address.get('phone', ''))
    desc.appendChild(desc_text)
    pt = doc.createElement("Point")
    pm.appendChild(pt)
    coords = doc.createElement("coordinates")
    pt.appendChild(coords)
    coords_text = doc.createTextNode('%(longitude)s,%(latitude)s,0' % address)
    coords.appendChild(coords_text)
    return doc</pre>
<p>To use this method to build our KML document from the list of addresses, we add the following code:</p>
<pre style="background: #e0e0e0; color: #000040; overflow: scroll;">        placemark = create_placemark(address)
        document.appendChild(placemark.documentElement)</pre>
<p>And finally, we need a way to print the whole document to stdout:</p>
<pre style="background: #e0e0e0; color: #000040; overflow: scroll;">print kml_doc.toprettyxml(indent="  ", encoding='UTF-8')</pre>
<h3>Generating KML to Make Google Happy</h3>
<p>If we upload this file to a web server, and point to its URL from Google Maps, we have a problem.  It doesn&#8217;t work.  Apparently Google doesn&#8217;t like the default pretty formatting of our KML, in particular the nodes containing only text, because of the extra newlines inserted before and after the text.  We can either turn off pretty printing, which I&#8217;d rather not do since it makes the output hard to read, or apply this little monkey patch to fix the problem:</p>
<pre style="background: #e0e0e0; color: #000040; overflow: scroll;">class Element(xml.dom.minidom.Element):

    def writexml(self, writer, indent="", addindent="", newl=""):
        # indent = current indentation
        # addindent = indentation to add to higher levels
        # newl = newline string
        writer.write(indent+"&lt;" + self.tagName)

        attrs = self._get_attributes()
        a_names = attrs.keys()
        a_names.sort()

        for a_name in a_names:
            writer.write(" %s=\"" % a_name)
            xml.dom.minidom._write_data(writer, attrs[a_name].value)
            writer.write("\"")
        if self.childNodes:
            newl2 = newl
            if len(self.childNodes) == 1 and \
                self.childNodes[0].nodeType == xml.dom.minidom.Node.TEXT_NODE:
                indent, addindent, newl = "", "", ""
            writer.write("&gt;%s"%(newl))
            for node in self.childNodes:
                node.writexml(writer,indent+addindent,addindent,newl)
            writer.write("%s%s" % (indent,self.tagName,newl2))
        else:
            writer.write("/&gt;%s"%(newl))

# Monkey patch Element class to use our subclass instead.
xml.dom.minidom.Element = Element</pre>
<h3>Changing Placemark Styles</h3>
<p>KML files also support the notion of styles, which allow you to customize the appearance of your placemarks.  For this example, I&#8217;ll just use different colored icons provided by Google to correspond to the county in which the address is located (based on the &#8220;county&#8221; column in my CSV file).  The code below is used to generate the style elements for the KML document:</p>
<pre style="background: #e0e0e0; color: #000040; overflow: scroll;">def create_style(style_id, icon_href):
    """Create a new style for different placemark icons."""
    doc = xml.dom.minidom.Document()
    style = doc.createElement('Style')
    style.setAttribute('id', style_id)
    doc.appendChild(style)
    icon_style = doc.createElement('IconStyle')
    style.appendChild(icon_style)
    icon = doc.createElement('Icon')
    icon_style.appendChild(icon)
    href = doc.createElement('href')
    icon.appendChild(href)
    href_text = doc.createTextNode(icon_href)
    href.appendChild(href_text)
    return doc</pre>
<p>In our main function, we use this code to create three different styles:</p>
<pre style="background: #e0e0e0; color: #000040; overflow: scroll;">    style_doc = create_style('Wake', \
        'http://maps.google.com/mapfiles/kml/paddle/red-blank.png')
    document.appendChild(style_doc.documentElement)
    style_doc = create_style('Durham', \
        'http://maps.google.com/mapfiles/kml/paddle/blu-blank.png')
    document.appendChild(style_doc.documentElement)
    style_doc = create_style('Orange', \
        'http://maps.google.com/mapfiles/kml/paddle/wht-blank.png')
    document.appendChild(style_doc.documentElement)</pre>
<p>Now, we add this code to our create_placemark method in order to associate the placemark with a style based on the &#8220;county&#8221; field:</p>
<pre style="background: #e0e0e0; color: #000040; overflow: scroll;">    if address.get('county', ''):
        style_url = doc.createElement("styleUrl")
        pm.appendChild(style_url)
        style_url_text = doc.createTextNode('#%(county)s' % address)
        style_url.appendChild(style_url_text)</pre>
<p>And now there is a different colored icon associated with the addresses, based on county.</p>
<h3>Putting It All Together</h3>
<p>I&#8217;ve attached the final script combining all of the snippets above (minus my Google Maps API key).</p>
<p><a href="http://www.ninemoreminutes.com/wp-content/uploads/2009/12/makemaps.py_.txt">makemaps.py</a></p>
<p>To view the custom placemarks in your browser, you need to make the KML file available on the web, and enter its URL into the search field in Google Maps.  You can also generate a URL with a query string such as the following:</p>
<pre>http://maps.google.com/?q=&lt;kml-url&gt;</pre>
<p>Or view the results of my sample data:</p>
<p><a href="http://maps.google.com/?q=http://www.ninemoreminutes.com/bojomap.kml">http://maps.google.com/?q=http://www.ninemoreminutes.com/bojomap.kml</a></p>
<h3>And Then?</h3>
<p>It would be relatively simple to include this code in a web app to read addresses from a database and generate a KML file on the fly.  For use in any Python web framework you choose.</p>
<h3>And Then?</h3>
<p>No more &#8220;and then&#8221;.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ninemoreminutes.com/2009/12/google-maps-with-python-and-kml/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Scripting Software Updates</title>
		<link>http://www.ninemoreminutes.com/2009/06/scripting-software-updates/</link>
		<comments>http://www.ninemoreminutes.com/2009/06/scripting-software-updates/#comments</comments>
		<pubDate>Tue, 16 Jun 2009 19:59:40 +0000</pubDate>
		<dc:creator>chris</dc:creator>
				<category><![CDATA[Embedded]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[script]]></category>
		<category><![CDATA[shell]]></category>
		<category><![CDATA[software]]></category>
		<category><![CDATA[updates]]></category>

		<guid isPermaLink="false">http://www.ninemoreminutes.com/?p=141</guid>
		<description><![CDATA[I wrote a shell script that can periodically check a URL for updates. It can download and run another script to apply those updates, potentially overwriting the first script if the update mechanism needs to change.  I needed  a way to install the update script initially, so I wrote a Python script to read and [...]]]></description>
			<content:encoded><![CDATA[<p>I wrote a <a href="http://www.gnu.org/software/bash/">shell script</a> that can periodically check a <a href="http://en.wikipedia.org/wiki/Uniform_Resource_Locator">URL</a> for updates. It can download and run another script to apply those updates, potentially overwriting the first script if the update mechanism needs to change.  I needed  a way to install the update script initially, so I wrote a <a href="http://www.python.org/">Python</a> script to read and <a href="http://en.wikipedia.org/wiki/Escape_character">escape</a> each line of the update script, then generate an install script which can write the update script if it is not installed.  Following me so far?  Good.</p>
<p><span id="more-141"></span>So this update script is on an <a href="http://en.wikipedia.org/wiki/Embedded_Linux">embedded Linux</a> device and can be completely wiped away if the user does a factory reset or firmware update from the manufacturer.  If they do that, my enhancements to the device and my upgrade script are gone, making the device useless for the particular application.  Fortunately, the manufacturer gives me a way to store a one-line setting in an area of flash that doesn&#8217;t get erased.  And even better, the default firmware will read and <a href="http://en.wikipedia.org/wiki/Eval">evaluate</a> this one line setting in the shell on startup.  <a href="http://www.a-ha.com/">AHA</a>!</p>
<p>The aforementioned <a href="http://www.python.org/">Python</a> script also takes the install script, packs it into one line, escapes everything again, and creates a <a href="http://en.wikipedia.org/wiki/Installation_(computer_programs)">bootstrap</a> script, whose sole purpose is to write the one setting that gets read on startup, that runs the install script, which creates the update script, which periodically checks for updates to the whole thing.</p>
<p>And now my head hurts.  But it works!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ninemoreminutes.com/2009/06/scripting-software-updates/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
