diff --git a/examples/address_to_district.py b/examples/address_to_district.py index 39b8cb0..fa6c507 100755 --- a/examples/address_to_district.py +++ b/examples/address_to_district.py @@ -15,51 +15,85 @@ The CGI script takes two parameters: ''' import cgi -from polipoly import AddressToDistrictService +import re +from polipoly import AddressToDistrictService, GeocodingError GMAPS_API_KEY = 'define-me' -PATH_TO_CDFILES = '' +PATH_TO_CDFILES = 'cd99_110' -# run as a module -if __name__ == '__main__': +class ApiException(Exception): + # these codes are in the 300s to fit the sunlight API + STATUS_CODES = { + 300: 'Google returned a server error when attempting to geocode', + 301: 'Empty address string', + 302: 'Unknown address', + 303: 'Prohibited address', + 304: 'Unknown geocoding error', + 305: 'Address refers to a PO Box', + 306: 'Address does not fall within a congressional district', + 320: 'Too many requests to geocoding service'} + + def __init__(self, code): + self.code = code + + def __str__(self): + return '%d: %s' % (self.code, self.STATUS_CODES[self.code]) + +def main(): # get address field and output type fields = cgi.FieldStorage() - addr = fields.getvalue('address') + addr = fields.getvalue('address') or '' output = fields.getvalue('output') + + # discard blank addresses as error 301 + if re.match('^\s*$', addr): + raise ApiException(301) + + # discard PO Box addresses as error 305 + pobox = re.compile('[Pp]\.?[Oo]\.?\s*(?:box|Box|BOX)') + if pobox.search(addr): + raise ApiException(305) - # plaintext error if no address is provided - if addr is None: - print 'Content-type: text/plain\n' - print 'error: must provide address parameter' + # create service and get a district + service = AddressToDistrictService(GMAPS_API_KEY, PATH_TO_CDFILES) + try: + lat, lng, districts = service.address_to_district(addr) + except GeocodingError, ge: + # convert GeocodingError to API error code (300-303 and 320) + err_dict = {500: 300, 601: 301, 602: 302, 603: 303, 620: 320} + raise ApiException(err_dict.get(ge.code,304)) + + # 306: address did not fall within congressional district + if len(districts) == 0: + raise ApiException(306) + + # XML output + if output == 'xml': + dist_str = '\n'.join([' %s' % dist + for dist in districts]) + print 'Content-type: text/xml\n' + print ''' +
%s
+%s +%s + +%s + +
''' % (addr, lat, lng, dist_str) + + # JSON output (default) else: - # create service and find out districts - service = AddressToDistrictService(GMAPS_API_KEY, PATH_TO_CDFILES) - lat, lng, districts = service.address_to_district(addr) - - # JSON output (default) - if output is None or output == 'json': - print 'Content-type: application/json\n' - dist_str = ','.join(['{"state":"%s", "district":"%s"}' % dist - for dist in districts]) - print '''{"address":"%s", "latitude":"%s", "longitude":"%s", + dist_str = ','.join(['{"state":"%s", "district":"%s"}' % dist + for dist in districts]) + print 'Content-type: application/json\n' + print '''{"address":"%s", "latitude":"%s", "longitude":"%s", "districts": [ %s ] }''' % (addr, lat, lng, dist_str) - # XML output - elif output == 'xml': - print 'Content-type: text/xml\n' - dist_str = '\n'.join([' %s' % dist - for dist in districts]) - print ''' -
%s
- %s - %s - - %s - -
''' % (addr, lat, lng, dist_str) - - else: - print 'Content-type: text/plain\n' - print 'error: invalid output parameter specified' +if __name__ == '__main__': + try: + main() + except ApiException,e: + print 'Content-type: text/plain\n' + print e diff --git a/polipoly.py b/polipoly.py index 7dc24ef..a9188bd 100644 --- a/polipoly.py +++ b/polipoly.py @@ -74,19 +74,19 @@ class GeocodingError(Exception): See http://www.google.com/apis/maps/documentation/reference.html#GGeoStatusCode """ - STATUS_CODES = {'500': 'Unknown Geocoding Server Error', - '601': 'Empty Address', - '602': 'Unknown Address', - '603': 'Prohibited Address', - '610': 'Bad API Key', - '620': 'Too Many Requests'} + STATUS_CODES = {500: 'Unknown Geocoding Server Error', + 601: 'Empty Address', + 602: 'Unknown Address', + 603: 'Prohibited Address', + 610: 'Bad API Key', + 620: 'Too Many Requests'} def __init__(self, code): Exception.__init__(self) - self.code = code + self.code = int(code) def __str__(self): - return 'GeocodingError: %s - %s' % (self.code, + return 'GeocodingError: %d - %s' % (self.code, self.STATUS_CODES[self.code]) class ShapefileError(Exception): """ Exception for problems with census shapefiles."""