geopy-0.95.1/0000755€¢Þ:€+8~0000000000012123101075016631 5ustar mtigasPROPUBLICA\Domain Users00000000000000geopy-0.95.1/geopy/0000755€¢Þ:€+8~0000000000012123101075017754 5ustar mtigasPROPUBLICA\Domain Users00000000000000geopy-0.95.1/geopy/__init__.py0000644€¢Þ:€+8~0000000052712123077364022106 0ustar mtigasPROPUBLICA\Domain Users00000000000000from geopy.point import Point from geopy.location import Location from geopy import geocoders VERSION = (0, 95, 1) def get_version(): version = '%s.%s' % (VERSION[0], VERSION[1]) if VERSION[2]: version = '%s.%s' % (version, VERSION[2]) if VERSION[3:]: version = '%s.%s' % (version, VERSION[3]) return version geopy-0.95.1/geopy/distance.py0000644€¢Þ:€+8~0000003234112117720124022130 0ustar mtigasPROPUBLICA\Domain Users00000000000000from math import atan, tan, sin, cos, pi, sqrt, atan2, acos, asin from geopy.units import radians from geopy import units, util from geopy.point import Point # Average great-circle radius in kilometers, from Wikipedia. # Using a sphere with this radius results in an error of up to about 0.5%. EARTH_RADIUS = 6372.795 # From http://www.movable-type.co.uk/scripts/LatLongVincenty.html: # The most accurate and widely used globally-applicable model for the earth # ellipsoid is WGS-84, used in this script. Other ellipsoids offering a # better fit to the local geoid include Airy (1830) in the UK, International # 1924 in much of Europe, Clarke (1880) in Africa, and GRS-67 in South # America. America (NAD83) and Australia (GDA) use GRS-80, functionally # equivalent to the WGS-84 ellipsoid. ELLIPSOIDS = { # model major (km) minor (km) flattening 'WGS-84': (6378.137, 6356.7523142, 1 / 298.257223563), 'GRS-80': (6378.137, 6356.7523141, 1 / 298.257222101), 'Airy (1830)': (6377.563396, 6356.256909, 1 / 299.3249646), 'Intl 1924': (6378.388, 6356.911946, 1 / 297.0), 'Clarke (1880)': (6378.249145, 6356.51486955, 1 / 293.465), 'GRS-67': (6378.1600, 6356.774719, 1 / 298.25) } class Distance(object): def __init__(self, *args, **kwargs): kilometers = kwargs.pop('kilometers', 0) if len(args) == 1: # if we only get one argument we assume # it's a known distance instead of # calculating it first kilometers += args[0] elif len(args) > 1: for a, b in util.pairwise(args): kilometers += self.measure(a, b) kilometers += units.kilometers(**kwargs) self.__kilometers = kilometers def __add__(self, other): if isinstance(other, Distance): return self.__class__(self.kilometers + other.kilometers) else: raise TypeError( "Distance instance must be added with Distance instance." ) def __neg__(self): return self.__class__(-self.kilometers) def __sub__(self, other): return self + -other def __mul__(self, other): return self.__class__(self.kilometers * other) def __div__(self, other): if isinstance(other, Distance): return self.kilometers / other.kilometers else: return self.__class__(self.kilometers / other) def __abs__(self): return self.__class__(abs(self.kilometers)) def __nonzero__(self): return bool(self.kilometers) def measure(self, a, b): raise NotImplementedError def __repr__(self): return 'Distance(%s)' % self.kilometers def __str__(self): return '%s km' % self.__kilometers def __cmp__(self, other): if isinstance(other, Distance): return cmp(self.kilometers, other.kilometers) else: return cmp(self.kilometers, other) @property def kilometers(self): return self.__kilometers @property def km(self): return self.kilometers @property def meters(self): return units.meters(kilometers=self.kilometers) @property def m(self): return self.meters @property def miles(self): return units.miles(kilometers=self.kilometers) @property def mi(self): return self.miles @property def feet(self): return units.feet(kilometers=self.kilometers) @property def ft(self): return self.feet @property def nautical(self): return units.nautical(kilometers=self.kilometers) @property def nm(self): return self.nautical class GreatCircleDistance(Distance): """ Use spherical geometry to calculate the surface distance between two geodesic points. This formula can be written many different ways, including just the use of the spherical law of cosines or the haversine formula. The class attribute `RADIUS` indicates which radius of the earth to use, in kilometers. The default is to use the module constant `EARTH_RADIUS`, which uses the average great-circle radius. """ RADIUS = EARTH_RADIUS def measure(self, a, b): a, b = Point(a), Point(b) lat1, lng1 = radians(degrees=a.latitude), radians(degrees=a.longitude) lat2, lng2 = radians(degrees=b.latitude), radians(degrees=b.longitude) sin_lat1, cos_lat1 = sin(lat1), cos(lat1) sin_lat2, cos_lat2 = sin(lat2), cos(lat2) delta_lng = lng2 - lng1 cos_delta_lng, sin_delta_lng = cos(delta_lng), sin(delta_lng) central_angle = acos( # We're correcting from floating point rounding errors on very-near and exact points here min(1.0, sin_lat1 * sin_lat2 + cos_lat1 * cos_lat2 * cos_delta_lng)) # From http://en.wikipedia.org/wiki/Great_circle_distance: # Historically, the use of this formula was simplified by the # availability of tables for the haversine function. Although this # formula is accurate for most distances, it too suffers from # rounding errors for the special (and somewhat unusual) case of # antipodal points (on opposite ends of the sphere). A more # complicated formula that is accurate for all distances is: (below) d = atan2(sqrt((cos_lat2 * sin_delta_lng) ** 2 + (cos_lat1 * sin_lat2 - sin_lat1 * cos_lat2 * cos_delta_lng) ** 2), sin_lat1 * sin_lat2 + cos_lat1 * cos_lat2 * cos_delta_lng) return self.RADIUS * d def destination(self, point, bearing, distance=None): point = Point(point) lat1 = units.radians(degrees=point.latitude) lng1 = units.radians(degrees=point.longitude) bearing = units.radians(degrees=bearing) if distance is None: distance = self if isinstance(distance, Distance): distance = distance.kilometers d_div_r = float(distance) / self.RADIUS lat2 = asin( sin(lat1) * cos(d_div_r) + cos(lat1) * sin(d_div_r) * cos(bearing) ) lng2 = lng1 + atan2( sin(bearing) * sin(d_div_r) * cos(lat1), cos(d_div_r) - sin(lat1) * sin(lat2) ) return Point(units.degrees(radians=lat2), units.degrees(radians=lng2)) class VincentyDistance(Distance): """ Calculate the geodesic distance between two points using the formula devised by Thaddeus Vincenty, with an accurate ellipsoidal model of the earth. The class attribute `ELLIPSOID` indicates which ellipsoidal model of the earth to use. If it is a string, it is looked up in the `ELLIPSOIDS` dictionary to obtain the major and minor semiaxes and the flattening. Otherwise, it should be a tuple with those values. The most globally accurate model is WGS-84. See the comments above the `ELLIPSOIDS` dictionary for more information. """ ELLIPSOID = 'WGS-84' def measure(self, a, b): a, b = Point(a), Point(b) lat1, lng1 = radians(degrees=a.latitude), radians(degrees=a.longitude) lat2, lng2 = radians(degrees=b.latitude), radians(degrees=b.longitude) if isinstance(self.ELLIPSOID, basestring): major, minor, f = ELLIPSOIDS[self.ELLIPSOID] else: major, minor, f = self.ELLIPSOID delta_lng = lng2 - lng1 reduced_lat1 = atan((1 - f) * tan(lat1)) reduced_lat2 = atan((1 - f) * tan(lat2)) sin_reduced1, cos_reduced1 = sin(reduced_lat1), cos(reduced_lat1) sin_reduced2, cos_reduced2 = sin(reduced_lat2), cos(reduced_lat2) lambda_lng = delta_lng lambda_prime = 2 * pi iter_limit = 20 while abs(lambda_lng - lambda_prime) > 10e-12 and iter_limit > 0: sin_lambda_lng, cos_lambda_lng = sin(lambda_lng), cos(lambda_lng) sin_sigma = sqrt( (cos_reduced2 * sin_lambda_lng) ** 2 + (cos_reduced1 * sin_reduced2 - sin_reduced1 * cos_reduced2 * cos_lambda_lng) ** 2 ) if sin_sigma == 0: return 0 # Coincident points cos_sigma = ( sin_reduced1 * sin_reduced2 + cos_reduced1 * cos_reduced2 * cos_lambda_lng ) sigma = atan2(sin_sigma, cos_sigma) sin_alpha = ( cos_reduced1 * cos_reduced2 * sin_lambda_lng / sin_sigma ) cos_sq_alpha = 1 - sin_alpha ** 2 if cos_sq_alpha != 0: cos2_sigma_m = cos_sigma - 2 * ( sin_reduced1 * sin_reduced2 / cos_sq_alpha ) else: cos2_sigma_m = 0.0 # Equatorial line C = f / 16. * cos_sq_alpha * (4 + f * (4 - 3 * cos_sq_alpha)) lambda_prime = lambda_lng lambda_lng = ( delta_lng + (1 - C) * f * sin_alpha * ( sigma + C * sin_sigma * ( cos2_sigma_m + C * cos_sigma * ( -1 + 2 * cos2_sigma_m ** 2 ) ) ) ) iter_limit -= 1 if iter_limit == 0: raise ValueError("Vincenty formula failed to converge!") u_sq = cos_sq_alpha * (major ** 2 - minor ** 2) / minor ** 2 A = 1 + u_sq / 16384. * ( 4096 + u_sq * (-768 + u_sq * (320 - 175 * u_sq)) ) B = u_sq / 1024. * (256 + u_sq * (-128 + u_sq * (74 - 47 * u_sq))) delta_sigma = ( B * sin_sigma * ( cos2_sigma_m + B / 4. * ( cos_sigma * ( -1 + 2 * cos2_sigma_m ** 2 ) - B / 6. * cos2_sigma_m * ( -3 + 4 * sin_sigma ** 2 ) * ( -3 + 4 * cos2_sigma_m ** 2 ) ) ) ) s = minor * A * (sigma - delta_sigma) return s def destination(self, point, bearing, distance=None): point = Point(point) lat1 = units.radians(degrees=point.latitude) lng1 = units.radians(degrees=point.longitude) bearing = units.radians(degrees=bearing) if distance is None: distance = self if isinstance(distance, Distance): distance = distance.kilometers ellipsoid = self.ELLIPSOID if isinstance(ellipsoid, basestring): ellipsoid = ELLIPSOIDS[ellipsoid] major, minor, f = ellipsoid tan_reduced1 = (1 - f) * tan(lat1) cos_reduced1 = 1 / sqrt(1 + tan_reduced1 ** 2) sin_reduced1 = tan_reduced1 * cos_reduced1 sin_bearing, cos_bearing = sin(bearing), cos(bearing) sigma1 = atan2(tan_reduced1, cos_bearing) sin_alpha = cos_reduced1 * sin_bearing cos_sq_alpha = 1 - sin_alpha ** 2 u_sq = cos_sq_alpha * (major ** 2 - minor ** 2) / minor ** 2 A = 1 + u_sq / 16384. * ( 4096 + u_sq * (-768 + u_sq * (320 - 175 * u_sq)) ) B = u_sq / 1024. * (256 + u_sq * (-128 + u_sq * (74 - 47 * u_sq))) sigma = distance / (minor * A) sigma_prime = 2 * pi while abs(sigma - sigma_prime) > 10e-12: cos2_sigma_m = cos(2 * sigma1 + sigma) sin_sigma, cos_sigma = sin(sigma), cos(sigma) delta_sigma = B * sin_sigma * ( cos2_sigma_m + B / 4. * ( cos_sigma * ( -1 + 2 * cos2_sigma_m ) - B / 6. * cos2_sigma_m * ( -3 + 4 * sin_sigma ** 2) * ( -3 + 4 * cos2_sigma_m ** 2 ) ) ) sigma_prime = sigma sigma = distance / (minor * A) + delta_sigma sin_sigma, cos_sigma = sin(sigma), cos(sigma) lat2 = atan2( sin_reduced1 * cos_sigma + cos_reduced1 * sin_sigma * cos_bearing, (1 - f) * sqrt( sin_alpha ** 2 + ( sin_reduced1 * sin_sigma - cos_reduced1 * cos_sigma * cos_bearing ) ** 2 ) ) lambda_lng = atan2( sin_sigma * sin_bearing, cos_reduced1 * cos_sigma - sin_reduced1 * sin_sigma * cos_bearing ) C = f / 16. * cos_sq_alpha * (4 + f * (4 - 3 * cos_sq_alpha)) delta_lng = ( lambda_lng - (1 - C) * f * sin_alpha * ( sigma + C * sin_sigma * ( cos2_sigma_m + C * cos_sigma * ( -1 + 2 * cos2_sigma_m ** 2 ) ) ) ) final_bearing = atan2( sin_alpha, cos_reduced1 * cos_sigma * cos_bearing - sin_reduced1 * sin_sigma ) lng2 = lng1 + delta_lng return Point(units.degrees(radians=lat2), units.degrees(radians=lng2)) # Set the default distance formula to the most generally accurate. distance = VincentyDistance geopy-0.95.1/geopy/format.py0000644€¢Þ:€+8~0000000530612117720124021627 0ustar mtigasPROPUBLICA\Domain Users00000000000000from geopy import units # Unicode characters for symbols that appear in coordinate strings. DEGREE = unichr(176) PRIME = unichr(8242) DOUBLE_PRIME = unichr(8243) ASCII_DEGREE = '' ASCII_PRIME = "'" ASCII_DOUBLE_PRIME = '"' LATIN1_DEGREE = chr(176) HTML_DEGREE = '°' HTML_PRIME = '′' HTML_DOUBLE_PRIME = '″' XML_DECIMAL_DEGREE = '°' XML_DECIMAL_PRIME = '′' XML_DECIMAL_DOUBLE_PRIME = '″' XML_HEX_DEGREE = '&xB0;' XML_HEX_PRIME = '&x2032;' XML_HEX_DOUBLE_PRIME = '&x2033;' ABBR_DEGREE = 'deg' ABBR_ARCMIN = 'arcmin' ABBR_ARCSEC = 'arcsec' DEGREES_FORMAT = "%(degrees)d%(deg)s %(minutes)d%(arcmin)s %(seconds)s%(arcsec)s" UNICODE_SYMBOLS = {'deg': DEGREE, 'arcmin': PRIME, 'arcsec': DOUBLE_PRIME} ASCII_SYMBOLS = {'deg': ASCII_DEGREE, 'arcmin': ASCII_PRIME, 'arcsec': ASCII_DOUBLE_PRIME} LATIN1_SYMBOLS = {'deg': LATIN1_DEGREE, 'arcmin': ASCII_PRIME, 'arcsec': ASCII_DOUBLE_PRIME} HTML_SYMBOLS = {'deg': HTML_DEGREE, 'arcmin': HTML_PRIME, 'arcsec': HTML_DOUBLE_PRIME} XML_SYMBOLS = {'deg': XML_DECIMAL_DEGREE, 'arcmin': XML_DECIMAL_PRIME, 'arcsec': XML_DECIMAL_DOUBLE_PRIME} ABBR_SYMBOLS = {'deg': ABBR_DEGREE, 'arcmin': ABBR_ARCMIN, 'arcsec': ABBR_ARCSEC} def format_degrees(degrees, format=DEGREES_FORMAT, symbols=ASCII_SYMBOLS): arcminutes = units.arcminutes(degrees=degrees - int(degrees)) arcseconds = units.arcseconds(arcminutes=arcminutes - int(arcminutes)) format_dict = dict( symbols, degrees=degrees, minutes=abs(arcminutes), seconds=abs(arcseconds) ) return format % format_dict DISTANCE_FORMAT = "%(magnitude)s%(unit)s" DISTANCE_UNITS = { 'km': lambda d: d, 'm': lambda d: units.meters(kilometers=d), 'mi': lambda d: units.miles(kilometers=d), 'ft': lambda d: units.feet(kilometers=d), 'nm': lambda d: units.nautical(kilometers=d), 'nmi': lambda d: units.nautical(kilometers=d) } def format_distance(kilometers, format=DISTANCE_FORMAT, unit='km'): magnitude = DISTANCE_UNITS[unit](kilometers) return format % {'magnitude': magnitude, 'unit': unit} _DIRECTIONS = [ ('north', 'N'), ('north by east', 'NbE'), ('north-northeast', 'NNE'), ('northeast by north', 'NEbN'), ('northeast', 'NE'), ('northeast by east', 'NEbE'), ('east-northeast', 'ENE'), ('east by north', 'EbN'), ('east', 'E'), ('east by south', 'EbS'), ('east-southeast', 'ESE'), ('southeast by east', 'SEbE'), ('southeast', 'SE'), ('southeast by south', 'SEbS'), ] DIRECTIONS, DIRECTIONS_ABBR = zip(*_DIRECTIONS) ANGLE_DIRECTIONS = dict((n * 11.25, d) for n, d in enumerate(DIRECTIONS)) ANGLE_DIRECTIONS_ABBR = dict((n * 11.25, d) for n, d in enumerate(DIRECTIONS_ABBR)) def format_direction(degrees): passgeopy-0.95.1/geopy/geocoders/0000755€¢Þ:€+8~0000000000012123101075021726 5ustar mtigasPROPUBLICA\Domain Users00000000000000geopy-0.95.1/geopy/geocoders/__init__.py0000644€¢Þ:€+8~0000000072412117720124024047 0ustar mtigasPROPUBLICA\Domain Users00000000000000from geopy.geocoders.bing import Bing from geopy.geocoders.google import Google from geopy.geocoders.googlev3 import GoogleV3 from geopy.geocoders.dot_us import GeocoderDotUS from geopy.geocoders.geonames import GeoNames from geopy.geocoders.wiki_gis import MediaWiki from geopy.geocoders.wiki_semantic import SemanticMediaWiki from geopy.geocoders.yahoo import Yahoo from geopy.geocoders.openmapquest import OpenMapQuest from geopy.geocoders.mapquest import MapQuest geopy-0.95.1/geopy/geocoders/base.py0000644€¢Þ:€+8~0000000164312117720124023223 0ustar mtigasPROPUBLICA\Domain Users00000000000000class Geocoder(object): def __init__(self, format_string='%s'): self.format_string = format_string def geocode(self, location): raise NotImplementedError def reverse(self, point): raise NotImplementedError def geocode_one(self, location): results = self.geocode(location) first = None for result in results: if first is None: first = result else: raise GeocoderResultError("Geocoder returned more than one result!") if first is not None: return first else: raise GeocoderResultError("Geocoder returned no results!") def geocode_first(self, location): results = self.geocode(location) for result in results: return result return None class GeocoderError(Exception): pass class GeocoderResultError(GeocoderError): pass geopy-0.95.1/geopy/geocoders/bing.py0000644€¢Þ:€+8~0000000654612123100364023232 0ustar mtigasPROPUBLICA\Domain Users00000000000000try: import json except ImportError: try: import simplejson as json except ImportError: from django.utils import simplejson as json from urllib import urlencode from urllib2 import urlopen from geopy.geocoders.base import Geocoder from geopy.util import logger, decode_page, join_filter class Bing(Geocoder): """Geocoder using the Bing Maps API.""" def __init__(self, api_key, format_string='%s', output_format=None): """Initialize a customized Bing geocoder with location-specific address information and your Bing Maps API key. ``api_key`` should be a valid Bing Maps API key. ``format_string`` is a string containing '%s' where the string to geocode should be interpolated before querying the geocoder. For example: '%s, Mountain View, CA'. The default is just '%s'. ``output_format`` (DEPRECATED) is ignored """ if output_format != None: from warnings import warn warn('geopy.geocoders.bing.Bing: The `output_format` parameter is deprecated '+ 'and ignored.', DeprecationWarning) self.api_key = api_key self.format_string = format_string self.url = "http://dev.virtualearth.net/REST/v1/Locations?%s" def geocode(self, string, exactly_one=True): if isinstance(string, unicode): string = string.encode('utf-8') params = {'query': self.format_string % string, 'key': self.api_key } url = self.url % urlencode(params) return self.geocode_url(url, exactly_one) def geocode_url(self, url, exactly_one=True): logger.debug("Fetching %s..." % url) page = urlopen(url) return self.parse_json(page, exactly_one) def parse_json(self, page, exactly_one=True): """Parse a location name, latitude, and longitude from an JSON response.""" if not isinstance(page, basestring): page = decode_page(page) doc = json.loads(page) resources = doc['resourceSets'][0]['resources'] if exactly_one and len(resources) != 1: raise ValueError("Didn't find exactly one resource! " \ "(Found %d.)" % len(resources)) def parse_resource(resource): stripchars = ", \n" a = resource['address'] address = a.get('addressLine', '').strip(stripchars) city = a.get('locality', '').strip(stripchars) state = a.get('adminDistrict', '').strip(stripchars) zipcode = a.get('postalCode', '').strip(stripchars) country = a.get('countryRegion', '').strip(stripchars) city_state = join_filter(", ", [city, state]) place = join_filter(" ", [city_state, zipcode]) location = join_filter(", ", [address, place, country]) latitude = resource['point']['coordinates'][0] or None longitude = resource['point']['coordinates'][1] or None if latitude and longitude: latitude = float(latitude) longitude = float(longitude) return (location, (latitude, longitude)) if exactly_one: return parse_resource(resources[0]) else: return [parse_resource(resource) for resource in resources] geopy-0.95.1/geopy/geocoders/dot_us.py0000644€¢Þ:€+8~0000000617212123100433023600 0ustar mtigasPROPUBLICA\Domain Users00000000000000import getpass from urllib import urlencode from urllib2 import urlopen from geopy.geocoders.base import Geocoder from geopy import util import csv class GeocoderDotUS(Geocoder): def __init__(self, username=None, password=None, format_string='%s'): if username and (password is None): password = getpass.getpass( "geocoder.us password for %r: " % username ) self.format_string = format_string self.username = username self.__password = password def get_url(self): username = self.username password = self.__password if username and password: auth = '%s@%s:' % (username, password) resource = 'member/service/namedcsv' else: auth = '' resource = 'service/namedcsv' return 'http://%sgeocoder.us/%s' % (auth, resource) def geocode(self, query, exactly_one=True): if isinstance(query, unicode): query = query.encode('utf-8') query_str = self.format_string % query page = urlopen("%s?%s" % ( self.get_url(), urlencode({'address':query_str}) )) reader = csv.reader(page) places = [r for r in reader] # GeoNames only returns the closest match, no matter what. # #if exactly_one and len(places) != 1: # raise ValueError("Didn't find exactly one placemark! " \ # "(Found %d.)" % len(places)) # #if exactly_one: # return self._parse_result(places[0]) #else: # return [self._parse_result(place) for place in places] return self._parse_result(places[0]) @staticmethod def _parse_result(result): # turn x=y pairs ("lat=47.6", "long=-117.426") into dict key/value pairs: place = dict( filter(lambda x: len(x)>1, # strip off bits that aren't pairs (i.e. "geocoder modified" status string") map(lambda x: x.split('=', 1), result) # split the key=val strings into (key, val) tuples )) address = [ place.get('number', None), place.get('prefix', None), place.get('street', None), place.get('type', None), place.get('suffix', None) ] city = place.get('city', None) state = place.get('state', None) zip_code = place.get('zip', None) name = util.join_filter(", ", [ util.join_filter(" ", address), city, util.join_filter(" ", [state, zip_code]) ]) latitude = place.get('lat', None) longitude = place.get('long', None) if latitude and longitude: latlon = float(latitude), float(longitude) else: return None # TODO use Point/Location object API in 0.95 #if latitude and longitude: # point = Point(latitude, longitude) #else: # point = None #return Location(name, point, dict(result)) return name, latlon geopy-0.95.1/geopy/geocoders/geonames.py0000644€¢Þ:€+8~0000000533512123100427024104 0ustar mtigasPROPUBLICA\Domain Users00000000000000import xml.dom.minidom from urllib import urlencode from urllib2 import urlopen from geopy import util try: import json except ImportError: try: import simplejson as json except ImportError: from django.utils import simplejson as json from geopy.geocoders.base import Geocoder class GeoNames(Geocoder): def __init__(self, format_string=None, output_format=None, country_bias=None): if format_string != None: from warnings import warn warn('geopy.geocoders.geonames.GeoNames: The `format_string` parameter is deprecated.'+ ' (It has always been ignored for GeoNames.)', DeprecationWarning) if output_format != None: from warnings import warn warn('geopy.geocoders.geonames.GeoNames: The `output_format` parameter is deprecated '+ 'and now ignored.', DeprecationWarning) self.country_bias = country_bias self.url = "http://ws.geonames.org/searchJSON?%s" def geocode(self, string, exactly_one=True): if isinstance(string, unicode): string = string.encode('utf-8') params = { 'q': string } if self.country_bias: params['countryBias'] = self.country_bias url = self.url % urlencode(params) return self.geocode_url(url, exactly_one) def geocode_url(self, url, exactly_one=True): page = urlopen(url) return self.parse_json(page, exactly_one) def parse_json(self, page, exactly_one): if not isinstance(page, basestring): page = util.decode_page(page) doc = json.loads(page) places = doc.get('geonames', []) if not places: return None if exactly_one and len(places) != 1: raise ValueError("Didn't find exactly one code! " \ "(Found %d.)" % len(places)) def parse_code(place): latitude = place.get('lat', None) longitude = place.get('lng', None) if latitude and longitude: latitude = float(latitude) longitude = float(longitude) else: return None placename = place.get('name') state = place.get('adminCode1', None) country = place.get('countryCode', None) location = ', '.join(filter(lambda x: bool(x), [placename, state, country] )) return (location, (latitude, longitude)) if exactly_one: return parse_code(places[0]) else: return [parse_code(place) for place in places] geopy-0.95.1/geopy/geocoders/google.py0000644€¢Þ:€+8~0000001326312123100370023556 0ustar mtigasPROPUBLICA\Domain Users00000000000000from urllib import urlencode from urllib2 import urlopen try: import json except ImportError: try: import simplejson as json except ImportError: from django.utils import simplejson as json from geopy.geocoders.base import Geocoder,GeocoderError,GeocoderResultError from geopy import Point, Location, util from warnings import warn class Google(Geocoder): """Geocoder using the Google Maps API.""" def __init__(self, api_key=None, domain='maps.googleapis.com', format_string='%s'): """Initialize a customized Google geocoder with location-specific address information and your Google Maps API key. ``api_key`` should be a valid Google Maps API key. Required as per Google Geocoding API V2 docs, but the API works without a key in practice. ``domain`` should be the localized Google Maps domain to connect to. The default is 'maps.google.com', but if you're geocoding address in the UK (for example), you may want to set it to 'maps.google.co.uk' to properly bias results. ``format_string`` is a string containing '%s' where the string to geocode should be interpolated before querying the geocoder. For example: '%s, Mountain View, CA'. The default is just '%s'. """ warn('geopy.geocoders.google: The `geocoders.google.Google` geocoder uses the '+ 'older "V2" API and is deprecated and may be broken at any time. A '+ 'geocoder utilizing the "V3" API is available at '+ '`geocoders.googlev3.GoogleV3` and will become the default in a future '+ 'version. See RELEASES file and http://goo.gl/somDT for usage information.', DeprecationWarning ) if not api_key: raise ValueError( "The `geocoders.google.Google` (V2) API now requires the "+ "`api_key` argument. Please acquire and use an API key "+ "(http://goo.gl/EdoHX) or upgrade to "+ "the V3 API (`geocoders.googlev3.GoogleV3`), which does "+ "not require a key. ---- Please note that the V2 API is " + "deprecated and may not work after March 2013 or September 2013." ) if domain == "maps.google.com": raise ValueError( "The `geocoders.google.Google` (V2) API now requires the "+ "`domain` argument to be set to 'maps.googleapis.com'. Please "+ "change or remove your `domain` kwarg." ) self.api_key = api_key self.domain = domain self.format_string = format_string self.output_format = "json" @property def url(self): domain = self.domain.strip('/') return "http://%s/maps/geo?%%s" % domain def geocode(self, string, exactly_one=True): if isinstance(string, unicode): string = string.encode('utf-8') params = {'q': self.format_string % string, 'output': self.output_format.lower(), 'key': self.api_key, 'sensor': False } url = self.url % urlencode(params) return self.geocode_url(url, exactly_one) def geocode_url(self, url, exactly_one=True): util.logger.debug("Fetching %s..." % url) page = urlopen(url) dispatch = getattr(self, 'parse_' + self.output_format) return dispatch(page, exactly_one) def parse_json(self, page, exactly_one=True): if not isinstance(page, basestring): page = util.decode_page(page) doc = json.loads(page) places = doc.get('Placemark', []) if len(places) == 0: # Got empty result. Parse out the status code and raise an error if necessary. status = doc.get("Status", []) status_code = status["code"] self.check_status_code(status_code) return None elif exactly_one and len(places) != 1: raise ValueError("Didn't find exactly one placemark! " \ "(Found %d.)" % len(places)) def parse_place(place): location = place.get('address') longitude, latitude = place['Point']['coordinates'][:2] return (location, (latitude, longitude)) if exactly_one: return parse_place(places[0]) else: return [parse_place(place) for place in places] def check_status_code(self,status_code): if status_code == 400: raise GeocoderResultError("Bad request (Server returned status 400)") elif status_code == 500: raise GeocoderResultError("Unkown error (Server returned status 500)") elif status_code == 601: raise GQueryError("An empty lookup was performed") elif status_code == 602: raise GQueryError("No corresponding geographic location could be found for the specified location, possibly because the address is relatively new, or because it may be incorrect.") elif status_code == 603: raise GQueryError("The geocode for the given location could be returned due to legal or contractual reasons") elif status_code == 610: raise GBadKeyError("The api_key is either invalid or does not match the domain for which it was given.") elif status_code == 620: raise GTooManyQueriesError("The given key has gone over the requests limit in the 24 hour period or has submitted too many requests in too short a period of time.") class GBadKeyError(GeocoderError): pass class GQueryError(GeocoderResultError): pass class GTooManyQueriesError(GeocoderResultError): pass geopy-0.95.1/geopy/geocoders/googlev3.py0000644€¢Þ:€+8~0000001766112123100415024035 0ustar mtigasPROPUBLICA\Domain Users00000000000000'''Google Maps V3 geocoder. Largely adapted from the existing v2 geocoder with modifications made where possible to support the v3 api as well as to clean up the class without breaking its compatibility or diverging its api too far from the rest of the geocoder classes. ''' import base64 import hashlib import hmac from urllib import urlencode from urllib2 import urlopen try: import json except ImportError: try: import simplejson as json except ImportError: from django.utils import simplejson as json from geopy.geocoders.base import Geocoder, GeocoderResultError from geopy import util class GoogleV3(Geocoder): '''Geocoder using the Google Maps v3 API.''' def __init__(self, domain='maps.googleapis.com', protocol='http', client_id=None, secret_key=None): '''Initialize a customized Google geocoder. API authentication is only required for Google Maps Premier customers. ``domain`` should be the localized Google Maps domain to connect to. The default is 'maps.google.com', but if you're geocoding address in the UK (for example), you may want to set it to 'maps.google.co.uk' to properly bias results. ``protocol`` http or https. ``client_id`` Premier account client id. ``secret_key`` Premier account secret key. ''' super(GoogleV3, self).__init__() if protocol not in ('http', 'https'): raise ValueError, 'Supported protocols are http and https.' if client_id and not secret_key: raise ValueError, 'Must provide secret_key with client_id.' if secret_key and not client_id: raise ValueError, 'Must provide client_id with secret_key.' self.domain = domain.strip('/') self.protocol = protocol self.doc = {} if client_id and secret_key: self.client_id = client_id self.secret_key = secret_key self.premier = True else: self.premier = False def get_signed_url(self, params): '''Returns a Premier account signed url.''' params['client'] = self.client_id url_params = {'protocol': self.protocol, 'domain': self.domain, 'params': urlencode(params)} secret = base64.urlsafe_b64decode(self.secret_key) url_params['url_part'] = ( '/maps/api/geocode/json?%(params)s' % url_params) signature = hmac.new(secret, url_params['url_part'], hashlib.sha1) url_params['signature'] = base64.urlsafe_b64encode(signature.digest()) return ('%(protocol)s://%(domain)s%(url_part)s' '&signature=%(signature)s' % url_params) def get_url(self, params): '''Returns a standard geocoding api url.''' return 'http://%(domain)s/maps/api/geocode/json?%(params)s' % ( {'domain': self.domain, 'params': urlencode(params)}) def geocode_url(self, url, exactly_one=True): '''Fetches the url and returns the result.''' util.logger.debug("Fetching %s..." % url) page = urlopen(url) return self.parse_json(page, exactly_one) def geocode(self, string, bounds=None, region=None, language=None, sensor=False, exactly_one=True): '''Geocode an address. ``string`` (required) The address that you want to geocode. ``bounds`` (optional) The bounding box of the viewport within which to bias geocode results more prominently. ``region`` (optional) The region code, specified as a ccTLD ("top-level domain") two-character value. ``language`` (optional) The language in which to return results. See the supported list of domain languages. Note that we often update supported languages so this list may not be exhaustive. If language is not supplied, the geocoder will attempt to use the native language of the domain from which the request is sent wherever possible. ``sensor`` (required) Indicates whether or not the geocoding request comes from a device with a location sensor. This value must be either True or False. ''' if isinstance(string, unicode): string = string.encode('utf-8') params = { 'address': self.format_string % string, 'sensor': str(sensor).lower() } if bounds: params['bounds'] = bounds if region: params['region'] = region if language: params['language'] = language if not self.premier: url = self.get_url(params) else: url = self.get_signed_url(params) return self.geocode_url(url, exactly_one) def reverse(self, point, language=None, sensor=False, exactly_one=False): '''Reverse geocode a point. ``point`` (required) The textual latitude/longitude value for which you wish to obtain the closest, human-readable address ``language`` (optional) The language in which to return results. See the supported list of domain languages. Note that we often update supported languages so this list may not be exhaustive. If language is not supplied, the geocoder will attempt to use the native language of the domain from which the request is sent wherever possible. ``sensor`` (required) Indicates whether or not the geocoding request comes from a device with a location sensor. This value must be either True or False. ''' params = { 'latlng': point, 'sensor': str(sensor).lower() } if language: params['language'] = language if not self.premier: url = self.get_url(params) else: url = self.get_signed_url(params) return self.geocode_url(url, exactly_one) def parse_json(self, page, exactly_one=True): '''Returns location, (latitude, longitude) from json feed.''' if not isinstance(page, basestring): page = util.decode_page(page) self.doc = json.loads(page) places = self.doc.get('results', []) if not places: check_status(self.doc.get('status')) return None elif exactly_one and len(places) != 1: raise ValueError( "Didn't find exactly one placemark! (Found %d)" % len(places)) def parse_place(place): '''Get the location, lat, lng from a single json place.''' location = place.get('formatted_address') latitude = place['geometry']['location']['lat'] longitude = place['geometry']['location']['lng'] return (location, (latitude, longitude)) if exactly_one: return parse_place(places[0]) else: return [parse_place(place) for place in places] def check_status(status): '''Validates error statuses.''' if status == 'ZERO_RESULTS': raise GQueryError( 'The geocode was successful but returned no results. This may' ' occur if the geocode was passed a non-existent address or a' ' latlng in a remote location.') elif status == 'OVER_QUERY_LIMIT': raise GTooManyQueriesError( 'The given key has gone over the requests limit in the 24' ' hour period or has submitted too many requests in too' ' short a period of time.') elif status == 'REQUEST_DENIED': raise GQueryError( 'Your request was denied, probably because of lack of a' ' sensor parameter.') elif status == 'INVALID_REQUEST': raise GQueryError('Probably missing address or latlng.') else: raise GeocoderResultError('Unkown error.') class GQueryError(GeocoderResultError): '''Generic Google query error.''' pass class GTooManyQueriesError(GeocoderResultError): '''Raised when the query rate limit is hit.''' pass geopy-0.95.1/geopy/geocoders/mapquest.py0000644€¢Þ:€+8~0000000513512123100537024145 0ustar mtigasPROPUBLICA\Domain Users00000000000000try: import json except ImportError: try: import simplejson as json except ImportError: from django.utils import simplejson as json from urllib import urlencode from urllib2 import urlopen from geopy.geocoders.base import Geocoder from geopy.util import logger, decode_page, join_filter from geopy import util class MapQuest(Geocoder): def __init__(self, api_key='', format_string='%s'): """Initialize a MapQuest geocoder with address information and MapQuest API key. """ self.api_key = api_key self.format_string = format_string self.url = "http://www.mapquestapi.com/geocoding/v1/address" def geocode(self, location, exactly_one=True): if isinstance(location, unicode): location = location.encode('utf-8') params = {'location' : location} data = urlencode(params) page = urlopen(self.url + '?key=' + self.api_key + '&' + data).read() return self.parse_json(page, exactly_one) def parse_json(self, page, exactly_one=True): """Parse display name, latitude, and longitude from an JSON response.""" if not isinstance(page, basestring): page = decode_page(page) resources = json.loads(page) statuscode = resources.get('info').get('statuscode') if statuscode == 403: return "Bad API Key" resources = resources.get('results')[0].get('locations') if exactly_one and len(resources) != 1: from warnings import warn warn("Didn't find exactly one resource!" + \ "(Found %d.), use exactly_one=False\n" % len(resources) ) def parse_resource(resource): city = resource['adminArea5'] county = resource['adminArea4'] state = resource['adminArea3'] country = resource['adminArea1'] latLng = resource['latLng'] latitude, longitude = latLng.get('lat'), latLng.get('lng') location = join_filter(", ", [city, county, state,country]) if latitude and longitude: latitude = float(latitude) longitude = float(longitude) return (location, (latitude, longitude)) if exactly_one: return parse_resource(resources[0]) else: return [parse_resource(resource) for resource in resources] if __name__ == "__main__": mq = MapQuest("Dmjtd%7Clu612007nq%2C20%3Do5-50zah") print mq.geocode('Mount St. Helens') mq = MapQuest("hDmjtd%7Clu612007nq%2C20%3Do5-50zah") print mq.geocode('Mount St. Helens') geopy-0.95.1/geopy/geocoders/openmapquest.py0000644€¢Þ:€+8~0000000465212123100526025030 0ustar mtigasPROPUBLICA\Domain Users00000000000000try: import json except ImportError: try: import simplejson as json except ImportError: from django.utils import simplejson as json from urllib import urlencode from urllib2 import urlopen from geopy.geocoders.base import Geocoder from geopy.util import logger, decode_page, join_filter class OpenMapQuest(Geocoder): """Geocoder using the MapQuest Open Platform Web Services.""" def __init__(self, api_key='', format_string='%s'): """Initialize an Open MapQuest geocoder with location-specific address information, no API Key is needed by the Nominatim based platform. ``format_string`` is a string containing '%s' where the string to geocode should be interpolated before querying the geocoder. For example: '%s, Mountain View, CA'. The default is just '%s'. """ self.api_key = api_key self.format_string = format_string self.url = "http://open.mapquestapi.com/nominatim/v1/search?format=json&%s" def geocode(self, string, exactly_one=True): if isinstance(string, unicode): string = string.encode('utf-8') params = {'q': self.format_string % string} url = self.url % urlencode(params) logger.debug("Fetching %s..." % url) page = urlopen(url) return self.parse_json(page, exactly_one) def parse_json(self, page, exactly_one=True): """Parse display name, latitude, and longitude from an JSON response.""" if not isinstance(page, basestring): page = decode_page(page) resources = json.loads(page) if exactly_one and len(resources) != 1: from warnings import warn warn("Didn't find exactly one resource!" + \ "(Found %d.), use exactly_one=False\n" % len(resources) ) def parse_resource(resource): location = resource['display_name'] latitude = resource['lat'] or None longitude = resource['lon'] or None if latitude and longitude: latitude = float(latitude) longitude = float(longitude) return (location, (latitude, longitude)) if exactly_one: return parse_resource(resources[0]) else: return [parse_resource(resource) for resource in resources] geopy-0.95.1/geopy/geocoders/virtual_earth.py0000644€¢Þ:€+8~0000000027112117720124025156 0ustar mtigasPROPUBLICA\Domain Users00000000000000from warnings import warn warn('geopy.geocoders.virtual_earth: geocoders.virtual_earth is now geocoders.bing',DeprecationWarning) from geopy.geocoders.bing import Bing as VirtualEarth geopy-0.95.1/geopy/geocoders/wiki_gis.py0000644€¢Þ:€+8~0000000442112123100512024101 0ustar mtigasPROPUBLICA\Domain Users00000000000000from urllib import urlencode from urllib2 import urlopen import xml from xml.parsers.expat import ExpatError from geopy.geocoders.base import Geocoder,GeocoderError,GeocoderResultError from geopy import Point, Location, util class MediaWiki(Geocoder): def __init__(self, format_url, transform_string=None): """Initialize a geocoder that can parse MediaWiki pages with the GIS extension enabled. ``format_url`` is a URL string containing '%s' where the page name to request will be interpolated. For example: 'http://www.wiki.com/wiki/%s' ``transform_string`` is a callable that will make appropriate replacements to the input string before requesting the page. If None is given, the default transform_string which replaces ' ' with '_' will be used. It is recommended that you consider this argument keyword-only, since subclasses will likely place it last. """ self.format_url = format_url if callable(transform_string): self.transform_string = transform_string @classmethod def transform_string(cls, string): """Do the WikiMedia dance: replace spaces with underscores.""" return string.replace(' ', '_') def geocode(self, string): if isinstance(string, unicode): string = string.encode('utf-8') wiki_string = self.transform_string(string) url = self.format_url % wiki_string return self.geocode_url(url) def geocode_url(self, url): util.logger.debug("Fetching %s..." % url) page = urlopen(url) name, (latitude, longitude) = self.parse_xhtml(page) return (name, (latitude, longitude)) def parse_xhtml(self, page): soup = isinstance(page, BeautifulSoup) and page or BeautifulSoup(page) meta = soup.head.find('meta', {'name': 'geo.placename'}) name = meta and meta['content'] or None meta = soup.head.find('meta', {'name': 'geo.position'}) if meta: position = meta['content'] latitude, longitude = util.parse_geo(position) if latitude == 0 or longitude == 0: latitude = longitude = None else: latitude = longitude = None return (name, (latitude, longitude)) geopy-0.95.1/geopy/geocoders/wiki_semantic.py0000644€¢Þ:€+8~0000000757012117720124025144 0ustar mtigasPROPUBLICA\Domain Users00000000000000import xml.dom.minidom from geopy.geocoders.base import Geocoder from geopy.point import Point from geopy.location import Location from geopy import util try: from BeautifulSoup import BeautifulSoup except ImportError: util.logger.warn("BeautifulSoup was not found. " \ "The SemanticMediaWiki geocoder will not work.") try: set except NameError: from sets import Set as set class SemanticMediaWiki(Geocoder): def __init__(self, format_url, attributes=None, relations=None, prefer_semantic=False, transform_string=None): self.format_url = format_url self.attributes = attributes self.relations = relations self.prefer_semantic = prefer_semantic self.transform_string = transform_string def get_url(self, string): return self.format_url % self.transform_string(string) def parse_rdf_link(self, page, mime_type='application/rdf+xml'): """Parse the URL of the RDF link from the of ``page``.""" soup = BeautifulSoup(page) link = soup.head.find('link', rel='alternate', type=mime_type) return link and link['href'] or None def parse_rdf_things(self, data): dom = xml.dom.minidom.parseString(data) thing_map = {} things = dom.getElementsByTagName('smw:Thing') things.reverse() for thing in things: name = thing.attributes['rdf:about'].value articles = thing.getElementsByTagName('smw:hasArticle') things[name] = articles[0].attributes['rdf:resource'].value return (things, thing) def transform_semantic(self, string): """Normalize semantic attribute and relation names by replacing spaces with underscores and capitalizing the result.""" return string.replace(' ', '_').capitalize() def get_relations(self, thing, relations=None): if relations is None: relations = self.relations for relation in relations: relation = self.transform_semantic(relation) for node in thing.getElementsByTagName('relation:' + relation): resource = node.attributes['rdf:resource'].value yield (relation, resource) def get_attributes(self, thing, attributes=None): if attributes is None: attributes = self.attributes for attribute in attributes: attribute = self.transform_semantic(attribute) for node in thing.getElementsByTagName('attribute:' + attribute): value = node.firstChild.nodeValue.strip() yield (attribute, value) def get_thing_label(self, thing): return util.get_first_text(thing, 'rdfs:label') def geocode_url(self, url, attempted=None): if attempted is None: attempted = set() util.logger.debug("Fetching %s..." % url) page = urlopen(url) soup = BeautifulSoup(page) rdf_url = self.parse_rdf_link(soup) util.logger.debug("Fetching %s..." % rdf_url) page = urlopen(rdf_url) things, thing = self.parse_rdf(page) name = self.get_label(thing) attributes = self.get_attributes(thing) for attribute, value in attributes: latitude, longitude = util.parse_geo(value) if None not in (latitude, longitude): break if None in (latitude, longitude): relations = self.get_relations(thing) for relation, resource in relations: url = things.get(resource, resource) if url in tried: # Avoid cyclic relationships. continue tried.add(url) name, (latitude, longitude) = self.geocode_url(url, tried) if None not in (name, latitude, longitude): break return (name, (latitude, longitude)) geopy-0.95.1/geopy/geocoders/yahoo.py0000644€¢Þ:€+8~0000000607712123100524023427 0ustar mtigasPROPUBLICA\Domain Users00000000000000""" Wrapper to the Yahoo's new PlaceFinder API. (doc says that the API RELEASE 1.0 (22 JUNE 2010)) """ import xml.dom.minidom from geopy import util from geopy import Point from urllib import urlencode from urllib2 import urlopen from geopy.geocoders.base import Geocoder try: import json except ImportError: try: import simplejson as json except ImportError: from django.utils import simplejson as json class Yahoo(Geocoder): BASE_URL = "http://where.yahooapis.com/geocode?%s" def __init__(self, app_id, format_string='%s', output_format=None): self.app_id = app_id self.format_string = format_string if output_format != None: from warnings import warn warn('geopy.geocoders.yahoo.Yahoo: The `output_format` parameter is deprecated '+ 'and now ignored. JSON will be used internally.', DeprecationWarning) def geocode(self, string, exactly_one=True): if isinstance(string, unicode): string = string.encode('utf-8') params = {'location': self.format_string % string, 'appid': self.app_id, 'flags': 'J' } url = self.BASE_URL % urlencode(params) util.logger.debug("Fetching %s..." % url) return self.geocode_url(url, exactly_one) def geocode_url(self, url, exactly_one=True): page = urlopen(url) return self.parse_json(page, exactly_one) def parse_json(self, page, exactly_one=True): if not isinstance(page, basestring): page = util.decode_page(page) doc = json.loads(page) results = doc.get('ResultSet', []).get('Results', []) if not results: raise ValueError("No results found") elif exactly_one and len(results) != 1: raise ValueError("Didn't find exactly one placemark! " \ "(Found %d.)" % len(results)) def parse_result(place): line1, line2, line3, line4 = place.get('line1'), place.get('line2'), place.get('line3'), place.get('line4') address = util.join_filter(", ", [line1, line2, line3, line4]) city = place.get('city') state = place.get('state') country = place.get('country') location = util.join_filter(", ", [address, city, country]) lat, lng = place.get('latitude'), place.get('longitude') #if lat and lng: # point = Point(floatlat, lng) #else: # point = None return (location, (float(lat), float(lng))) if exactly_one: return parse_result(results[0]) else: return [parse_result(result) for result in results] def reverse(self, coord, exactly_one=True): (lat, lng) = coord params = {'location': '%s,%s' % (lat, lng), 'gflags' : 'R', 'appid': self.app_id, 'flags': 'J' } url = self.BASE_URL % urlencode(params) return self.geocode_url(url, exactly_one) geopy-0.95.1/geopy/geohash.py0000644€¢Þ:€+8~0000000473512117720124021762 0ustar mtigasPROPUBLICA\Domain Users00000000000000from geopy import Point class Geohash(object): ENCODE_MAP = '0123456789bcdefghjkmnpqrstuvwxyz' DECODE_MAP = dict([(char, i) for i, char in enumerate(ENCODE_MAP)]) def __init__(self, point_class=Point, precision=12): self.point_class = point_class self.precision = precision def encode(self, *args, **kwargs): precision = kwargs.pop('precision', self.precision) point = Point(*args, **kwargs) lat_min, latitude, lat_max = -90, 0, 90 long_min, longitude, long_max = -180, 0, 180 string = '' bytes = [] odd_bit = False for i in xrange(precision): byte = 0 for bit in (16, 8, 4, 2, 1): if odd_bit: if point.latitude >= latitude: byte |= bit lat_min = latitude else: lat_max = latitude latitude = (lat_min + lat_max) / 2. else: if point.longitude >= longitude: byte |= bit long_min = longitude else: long_max = longitude longitude = (long_min + long_max) / 2. odd_bit = not odd_bit bytes.append(byte) return ''.join([self.ENCODE_MAP[byte] for byte in bytes]) def decode(self, string): lat_min, latitude, lat_max = -90, 0, 90 long_min, longitude, long_max = -180, 0, 180 odd_bit = False for char in string: try: byte = self.DECODE_MAP[char] except KeyError: raise ValueError("Invalid hash: unexpected character %r." % (c,)) else: for bit in (16, 8, 4, 2, 1): if odd_bit: if byte & bit: lat_min = latitude else: lat_max = latitude latitude = (lat_min + lat_max) / 2. else: if byte & bit: long_min = longitude else: long_max = longitude longitude = (long_min + long_max) / 2. odd_bit = not odd_bit point = self.point_class((latitude, longitude)) point.error = (lat_max - latitude, long_max - longitude) return point geopy-0.95.1/geopy/location.py0000644€¢Þ:€+8~0000000152212117720124022143 0ustar mtigasPROPUBLICA\Domain Users00000000000000from geopy.point import Point class Location(object): def __init__(self, name="", point=None, attributes=None, **kwargs): self.name = name if point is not None: self.point = Point(point) if attributes is None: attributes = {} self.attributes = dict(attributes, **kwargs) def __getitem__(self, index): """Backwards compatibility with geopy 0.93 tuples.""" return (self.name, self.point)[index] def __repr__(self): return "Location(%r, %r)" % (self.name, self.point) def __iter__(self): return iter((self.name, self.point)) def __eq__(self, other): return (self.name, self.point) == (other.name, other.point) def __ne__(self, other): return (self.name, self.point) != (other.name, other.point) geopy-0.95.1/geopy/parsers/0000755€¢Þ:€+8~0000000000012123101075021433 5ustar mtigasPROPUBLICA\Domain Users00000000000000geopy-0.95.1/geopy/parsers/__init__.py0000644€¢Þ:€+8~0000000017212117720124023551 0ustar mtigasPROPUBLICA\Domain Users00000000000000from warnings import warn warn('geopy.parsers is deprecated.', DeprecationWarning) from geopy.parsers.base import Parser geopy-0.95.1/geopy/parsers/base.py0000644€¢Þ:€+8~0000000043212117720124022723 0ustar mtigasPROPUBLICA\Domain Users00000000000000class Parser(object): def find(self, document): raise NotImplementedError def find_first(self, document): for location in self.find_iter(document): return location def find_all(self, document): return list(self.find(document)) geopy-0.95.1/geopy/parsers/gpx.py0000644€¢Þ:€+8~0000003053712117720124022620 0ustar mtigasPROPUBLICA\Domain Users00000000000000from geopy import Point from geopy.parsers.iso8601 import parse_iso8601 import sys, re from xml.etree import ElementTree class VersionError(Exception): pass class Waypoint(Point): ''' A `Waypoint` is a geopy `Point` with additional waypoint metadata as defined by the GPX format specification. ''' @classmethod def from_xml_names(cls, attrs, children): ''' Construct a new Waypoint from dictionaries of attribute and child element names corresponding to GPX waypoint information, as parsed by the `GPX` class. ''' lat = attrs['lat'] lon = attrs['lon'] if 'ele' in children: ele = children['ele'] else: ele = None w = cls(lat, lon, ele) if 'time' in children: w.timestamp = children['time'] if 'name' in children: w.name = children['name'] if 'desc' in children: w.description = children['desc'] if 'cmt' in children: w.comment = children['cmt'] if 'src' in children: w.source = children['src'] if 'sym' in children: w.symbol = children['sym'] if 'type' in children: w.classification = children['type'] if 'fix' in children: w.fix = children['fix'] if 'sat' in children: w.num_satellites = children['sat'] if 'ageofdgpsdata' in children: w.age = children['ageofdgpsdata'] if 'dgpsid' in children: w.dgpsid = children['dgpsid'] return w class _Attr(object): ''' Value wrapper for allowing interfaces to access attribute values with `obj.text` ''' def __init__(self, value): self.text = value class GPX(object): GPX_NS = "http://www.topografix.com/GPX/1/1" FILE_EXT = '.gpx' MIME_TYPE = 'application/gpx+xml' VERSION = '1.1' FIX_TYPES = set(('none', '2d', '3d', 'dgps', 'pps')) DECIMAL_RE = re.compile(r'([+-]?\d*\.?\d+)$') # Each "type tuple" is a tuple of two items: # 1. Dictionary of attributes in the type # 2. Dictionary of child elements that can appear in the type GPX_TYPE = ({'version': 'string', 'creator': 'string'}, { 'metadata': 'metadata', 'wpt': ['waypoint'], 'rte': ['route'], 'trk': ['track'], 'extensions': 'extensions' }) METADATA_TYPE = ({}, { 'name': 'string', 'desc': 'string', 'author': 'person', 'copyright': 'copyright', 'link': ['link'], 'time': 'datetime', 'keywords': 'string', 'bounds': 'bounds', 'extensions': 'extensions' }) WAYPOINT_TYPE = ({'lat': 'decimal', 'lon': 'decimal'}, { 'ele': 'decimal', 'time': 'datetime', 'magvar': 'degrees', 'geoidheight': 'decimal', 'name': 'string', 'cmt': 'string', 'desc': 'string', 'src': 'string', 'link': ['link'], 'sym': 'string', 'type': 'string', 'fix': 'fix', 'sat': 'unsigned', 'hdop': 'decimal', 'vdop': 'decimal', 'pdop': 'decimal', 'ageofdgpsdata': 'decimal', 'dgpsid': 'dgpsid', 'extensions': 'extensions' }) ROUTE_TYPE = ({}, { 'name': 'string', 'cmt': 'string', 'desc': 'string', 'src': 'string', 'link': ['link'], 'number': 'unsigned', 'type': 'string', 'extensions': 'extensions', 'rtept': ['waypoint'] }) TRACK_TYPE = ({}, { 'name': 'string', 'cmt': 'string', 'desc': 'string', 'src': 'string', 'link': ['link'], 'number': 'unsigned', 'type': 'string', 'extensions': 'extensions', 'trkseg': ['segment'] }) TRACK_SEGMENT_TYPE = ({}, {'trkpt': ['waypoint'], 'extensions': 'extensions'} ) COPYRIGHT_TYPE = ( {'author': 'string'}, {'year': 'year', 'license': 'uri'} ) LINK_TYPE = ({'href': 'uri'}, {'text': 'string', 'type': 'string'}) EMAIL_TYPE = ({'id': 'string', 'domain': 'string'}, {}) PERSON_TYPE = ({}, {'name': 'string', 'email': 'email', 'link': 'link'}) POINT_TYPE = ({'lat': 'longitude', 'lon': 'longitude'}, {'ele': 'decimal', 'time': 'datetime'} ) POINT_SEGMENT_TYPE = ({}, {'pt': ['point']}) BOUNDS_TYPE = ({ 'minlat': 'latitude', 'minlon': 'longitude', 'maxlat': 'latitude', 'maxlon': 'longitude' }, {}) def __init__(self, document=None, cache=True): self.cache = cache self._waypoints = {} self._routes = {} self._tracks = {} self.type_handlers = { 'string': lambda e: e.text, 'uri': lambda e: e.text, 'datetime': self._parse_datetime_element, 'decimal': self._parse_decimal, 'dgpsid': self._parse_dgps_station, 'email': self._parse_email, 'link': self._parse_link, 'year': self._parse_int, 'waypoint': self._parse_waypoint, 'segment': self._parse_segment, 'unsigned': self._parse_unsigned, 'degrees': self._parse_degrees, 'fix': self._parse_fix, 'extensions': self._parse_noop, } if document is not None: self.open(document) def open(self, string_or_file): if isinstance(string_or_file, basestring): string_or_file = ElementTree.fromstring(string_or_file) elif not ElementTree.iselement(string_or_file): string_or_file = ElementTree.parse(string_or_file) if string_or_file.getroot().tag == self._get_qname('gpx'): self._root = string_or_file.getroot() @property def version(self): if not hasattr(self, '_version'): version = self._root.get('version') if version == self.VERSION: self._version = version else: raise VersionError("%r" % (version,)) return self._version @property def creator(self): if not hasattr(self, '_creator'): self._creator = self._root.get('creator') return self._creator @property def metadata(self): if not hasattr(self, '_metadata'): metadata_qname = self._get_qname('metadata') metadata = {} element = self._root.find(metadata_qname) if element is not None: single, multi = self.METADATA metadata.update(self._child_dict(element, single, multi)) for tag in ('name', 'desc', 'time', 'keywords'): if tag in metadata: metadata[tag] = metadata[tag] if 'time' in metadata: metadata['time'] = self._parse_datetime(metadata['time']) self._metadata = metadata return self._metadata @property def waypoints(self): tag = self._get_qname('wpt') return self._cache_parsed(tag, self._parse_waypoint, self._waypoints) def _parse_waypoint(self, element): waypoint = {} point = Point(element.get('lat'), element.get('lon')) def _parse_segment(self, element): pass @property def routes(self): tag = self._get_qname('rte') return self._cache_parsed(tag, self._parse_route, self._routes) def _parse_route(self, element): pass @property def route_names(self): for route in self._root.findall(self._get_qname('rte')): yield route.findtext(self._get_qname('name')) @property def waypoints(self): return self.get_waypoints() def get_waypoints(self, route=None): if route is None: root = self._root waypoint_name = self._get_qname('wpt') else: root = self.get_route_by_name(route) waypoint_name = self._get_qname('rtept') for rtept in root.findall(waypoint_name): attrs, children = self._parse_type(rtept, self.WAYPOINT_TYPE) yield Waypoint.from_xml_names(attrs, children) def get_route_by_name(self, route): if isinstance(route, basestring): name = route index = 0 else: name, index = route seen_index = 0 for rte in self._root.findall(self._get_qname('rte')): rname = rte.findtext(self._get_qname('name')) if rname == name: if not seen_index == index: seen_index = seen_index + 1 else: return rte return None @property def tracks(self): tag = self._get_qname('rte') return self._cache_parsed(tag, self._parse_track, self._tracks) def _parse_track(self, element): pass def _parse_type(self, element, type_def): attr_types, child_types = type_def attrs = {} children = {} for attr, handler in attr_types.iteritems(): value = element.get(attr) type_func = self.type_handlers[handler] attrs[attr] = type_func(_Attr(value)) for tag, handler in child_types.iteritems(): values = [] all = False if isinstance(handler, list): all = True type_func = self.type_handlers[handler[0]] else: type_func = self.type_handlers[handler] for e in element.findall(self._get_qname(tag)): values.append(type_func(e)) if len(values) > 0: if all: children[tag] = values else: children[tag] = values[-1] return attrs, children @property def extensions(self): extensions_qname = self._get_qname('extensions') def _cache_parsed(self, tag, parse_func, cache): i = -1 for i in xrange(len(cache)): item = cache[i] if item is not None: yield item for element in self._root: if element.tag == tag: i += 1 item = parse_func(element) if self.cache: cache[i] = item if item is not None: yield item def _parse_decimal(self, element): value = element.text match = re.match(self.DECIMAL_RE, value) if match: return float(match.group(1)) else: raise ValueError("Invalid decimal value: %r" % (value,)) def _parse_degrees(self, element): value = self._parse_decimal(element) if 0 <= value <= 360: return value else: raise ValueError("Value out of range [0, 360]: %r" % (value,)) def _parse_dgps_station(self, element): value = int(element.text) if 0 <= value <= 1023: return value else: raise ValueError("Value out of range [0, 1023]: %r" % (value,)) def _parse_datetime(self, value): return parse_iso8601(value) def _parse_datetime_element(self, element): return self._parse_datetime(element.text) def _parse_email(self, element): value = element.text if not value: name = element.get('id') domain = element.get('domain') if name and domain: return '@'.join((name, domain)) return value or None def _parse_link(self, element): pass def _parse_int(self, element): return int(element.text) def _parse_unsigned(self, element): return int(element.text) def _parse_fix(self, element): value = element.text if value in self.FIX_TYPES: return value else: raise ValueError("Value is not a valid fix type: %r" % (value,)) def _parse_string(self, element): return element.text def _parse_noop(self, element): return element def _child_dict(self, element, single, multi): single = dict([(self._get_qname(tag), tag) for tag in single]) multi = dict([(self._get_qname(tag), tag) for tag in multi]) limit = len(single) d = {} if limit or multi: for child in element: if child.tag in single: name = single.pop(child.tag) d[name] = child limit -= 1 elif child.tag in multi: name = multi[child.tag] d.setdefault(name, []).append(child) if not limit and not multi: break return d def _get_qname(self, name): return "{%s}%s" % (self.GPX_NS, name) geopy-0.95.1/geopy/parsers/html.py0000644€¢Þ:€+8~0000001276112117720124022765 0ustar mtigasPROPUBLICA\Domain Users00000000000000import re from BeautifulSoup import BeautifulSoup, SoupStrainer from geopy import Point, Location from geopy.parsers import Parser from geopy.util import unescape FLOAT_RE = re.compile(r'([+-]?\d*\.?\d+)$') class ICBMMetaTag(Parser): META_NAME = 'ICBM' def __init__(self, ignore_invalid=True): self.ignore_invalid = ignore_invalid def find(self, document): strainer = SoupStrainer('meta', attrs={'name': self.META_NAME}) if not isinstance(document, BeautifulSoup): elements = BeautifulSoup(document, parseOnlyThese=strainer) else: elements = document.findAll(strainer) for element in elements: lat_long = element.get('content') if lat_long or not self.ignore_invalid: try: point = Point(unescape(lat_long)) except (TypeError, ValueError): if not self.ignore_invalid: raise else: yield Location(None, point) class GeoMetaTag(Parser): META_NAME = re.compile(r'geo\.(\w+)') def __init__(self, ignore_invalid=True): self.ignore_invalid = ignore_invalid def find(self, document): strainer = SoupStrainer('meta', attrs={'name': self.META_NAME}) if not isinstance(document, BeautifulSoup): elements = BeautifulSoup(document, parseOnlyThese=strainer) else: elements = document.findAll(strainer) attrs = {} for element in elements: meta_name = element['name'] attr_name = re.match(self.META_NAME, meta_name).group(1) value = element.get('content') if attr_name in attrs: location = self._get_location(attrs) if location is not None: yield location attrs.clear() attrs[attr_name] = value and unescape(value) location = self._get_location(attrs) if location is not None: yield location def _get_location(self, attrs): position = attrs.pop('position') name = attrs.pop('placename') if position is not None: if position or not self.ignore_invalid: try: point = Point(position) except (TypeError, ValueError): if not self.ignore_invalid: raise else: return Location(name, point, attrs) class GeoMicroformat(Parser): GEO_CLASS = re.compile(r'\s*geo\s*') LATITUDE_CLASS = re.compile(r'\s*latitude\s*') LONGITUDE_CLASS = re.compile(r'\s*longitude\s*') VALUE_CLASS = re.compile(r'\s*value\s*') SEP = re.compile(r'\s*;\s*') def __init__(self, ignore_invalid=True, shorthand=True, abbr_title=True, value_excerpting=True): self.ignore_invalid = ignore_invalid self.shorthand = shorthand self.abbr_title = abbr_title self.value_excerpting = value_excerpting def find(self, document): strainer = SoupStrainer(attrs={'class': self.GEO_CLASS}) if not isinstance(document, BeautifulSoup): elements = BeautifulSoup(document, parseOnlyThese=strainer) else: elements = document.findAll(strainer) for element in elements: preformatted = element.name == 'pre' lat_element = element.find(attrs={'class': self.LATITUDE_CLASS}) long_element = element.find(attrs={'class': self.LONGITUDE_CLASS}) latitude = None longitude = None if lat_element and long_element: latitude = self._get_value(lat_element, preformatted) longitude = self._get_value(long_element, preformatted) elif self.shorthand: lat_long = re.split(self.SEP, self._get_value(element), 1) if len(lat_long) == 2: latitude, longitude = lat_long if latitude and longitude: lat_match = FLOAT_RE.match(unescape(latitude)) long_match = FLOAT_RE.match(unescape(longitude)) if lat_match and long_match: latitude = float(lat_match.group(1)) longitude = float(long_match.group(1)) text = unescape(self._get_text(element).strip()) name = re.sub('\s+', ' ', text) yield Location(name, (latitude, longitude)) def _get_text(self, element, preformatted=False): if isinstance(element, basestring): if not preformatted: return re.sub('\s+', ' ', element) else: return element elif element.name == 'br': return '\n' else: pre = preformatted or element.name == 'pre' return "".join([self._get_text(node, pre) for node in element]) def _get_value(self, element, preformatted=False): if self.value_excerpting: value_nodes = element.findAll(attrs={'class': self.VALUE_CLASS}) if value_nodes: pre = preformatted or element.name == 'pre' values = [self._get_text(node, pre) for node in value_nodes] return "".join(values) if self.abbr_title and element.name == 'abbr': value = element.get('title') if value is not None: return value return self._get_text(element, preformatted) geopy-0.95.1/geopy/parsers/iso8601.py0000644€¢Þ:€+8~0000000366312117720124023133 0ustar mtigasPROPUBLICA\Domain Users00000000000000import re from datetime import datetime, timedelta, tzinfo ISO8601_RE = re.compile(r""" (?P\d{2,4}) (?:-?(?P[01]\d))? (?:-?(?P
[0-3]\d))? (?:T (?P[0-2]\d) (?::?(?P[0-5]\d))? (?::?(?P[0-5]\d))? (?:[,.](?P\d+))? )? (?PZ| (?P[+-][0-2]\d) (?::?(?P[0-5]\d))? )? """, re.X ) def to_int(str_or_none, default=0): if str_or_none is not None: return int(str_or_none) return default def parse_iso8601(string): match = ISO8601_RE.match(string) if match is None: raise ValueError("Invalid ISO 8601 timestamp") d = match.groupdict() year, month, day = d['YYYY'], d['MM'], d['DD'] hour, minute, second, fraction = d['hh'], d['mm'], d['ss'], d['s'] zone, zone_hours, zone_minutes = d['TZD'], d['zh'], d['zm'] if zone: if zone == 'Z': tz = TimeZone("UTC") else: hours = to_int(zone_hours, 0) minutes = to_int(zone_minutes, 0) * -int(hours < 0) tz = TimeZone(zone, timedelta(hours=hours, minutes=minutes)) else: tz = None timestamp = datetime( int(year), to_int(month, 1), to_int(day, 1), to_int(hour, 0), to_int(minute, 0), to_int(second, 0), tzinfo=tz ) fraction = fraction and float('.' + fraction) or 0 if fraction: if second is not None: timestamp += timedelta(seconds=fraction) elif minute is not None: timestamp += timedelta(minutes=fraction) elif hour is not None: timestamp += timedelta(hours=fraction) return timestamp class TimeZone(tzinfo): def __init__(self, name, offset=timedelta(0)): self.__name = name self.__offset = offset def utcoffset(self, dt): return self.__offset def tzname(self, dt): return self.__name def dst(self, dt): return timedelta(0) geopy-0.95.1/geopy/parsers/rdf.py0000644€¢Þ:€+8~0000000375212117720124022574 0ustar mtigasPROPUBLICA\Domain Users00000000000000try: import xml.etree except ImportError: import ElementTree else: from xml.etree import ElementTree from geopy import Point, Location from geopy.parsers import Parser from geopy.util import reversed class GeoVocabulary(Parser): GEO_NS = "http://www.w3.org/2003/01/geo/wgs84_pos#" POINT_CLASS = 'Point' LATITUDE_PROPERTY = 'lat' LONGITUDE_PROPERTY = 'long' ALTITUDE_PROPERTY = 'alt' def __init__(self, ignore_invalid=True, point_class=False): self.ignore_invalid = ignore_invalid self.point_class = point_class def find(self, document): if isinstance(document, basestring): document = ElementTree.fromstring(document) elif not ElementTree.iselement(document): document = ElementTree.parse(document) point_qname = self._get_qname(self.POINT_CLASS) lat_qname = self._get_qname(self.LATITUDE_PROPERTY) long_qname = self._get_qname(self.LONGITUDE_PROPERTY) alt_qname = self._get_qname(self.ALTITUDE_PROPERTY) queue = [document] while queue: element = queue.pop() if not self.point_class or element.tag == point_qname: lat_el = element.find(lat_qname) long_el = element.find(long_qname) alt_el = element.find(alt_qname) if lat_el is not None and long_el is not None: latitude = lat_el.text longitude = long_el.text altitude = alt_el and alt_el.text try: point = Point((latitude, longitude, altitude)) except (TypeError, ValueError): if not self.ignore_invalid: raise else: yield Location(None, point) queue.extend(reversed(element)) def _get_qname(self, name): return "{%s}%s" % (self.GEO_NS, name) geopy-0.95.1/geopy/point.py0000644€¢Þ:€+8~0000002460312117720124021471 0ustar mtigasPROPUBLICA\Domain Users00000000000000import re from itertools import islice from geopy import util, units, format class Point(object): """ A geodetic point with latitude, longitude, and altitude. Latitude and longitude are floating point values in degrees. Altitude is a floating point value in kilometers. The reference level is never considered and is thus application dependent, so be consistent! The default for all values is 0. Points can be created in a number of ways... With longitude, latitude, and altitude: >>> p1 = Point(41.5, -81, 0) >>> p2 = Point(latitude=41.5, longitude=-81) With a sequence of 0 to 3 values (longitude, latitude, altitude): >>> p1 = Point([41.5, -81, 0]) >>> p2 = Point((41.5, -81)) Copy another `Point` instance: >>> p2 = Point(p1) >>> p2 == p1 True >>> p2 is p1 False Give an object with a 'point' attribute, such as a `Location` instance: >>> p = Point(location) Give a string containing at least latitude and longitude: >>> p1 = Point('41.5,-81.0') >>> p2 = Point('41.5 N -81.0 W') >>> p3 = Point('-41.5 S, 81.0 E, 2.5km') >>> p4 = Point('23 26m 22s N 23 27m 30s E 21.0mi') >>> p5 = Point('''3 26' 22" N 23 27' 30" E''') Point values can be accessed by name or by index: >>> p = Point(41.5, -81.0, 0) >>> p.latitude == p[0] True >>> p.longitude == p[1] True >>> p.altitude == p[2] True When unpacking (or iterating), a (latitude, longitude, altitude) tuple is returned >>> latitude, longitude, altitude = p """ UTIL_PATTERNS = dict( FLOAT=r'\d+(?:\.\d+)?', DEGREE=format.DEGREE, PRIME=format.PRIME, DOUBLE_PRIME=format.DOUBLE_PRIME, SEP=r'\s*[,;\s]\s*' ) POINT_PATTERN = re.compile(r""" \s* (?P (?P-?%(FLOAT)s)(?:[%(DEGREE)s ][ ]* (?:(?P%(FLOAT)s)[%(PRIME)s'm][ ]*)? (?:(?P%(FLOAT)s)[%(DOUBLE_PRIME)s"s][ ]*)? )?(?P[NS])?) %(SEP)s (?P (?P-?%(FLOAT)s)(?:[%(DEGREE)s\s][ ]* (?:(?P%(FLOAT)s)[%(PRIME)s'm][ ]*)? (?:(?P%(FLOAT)s)[%(DOUBLE_PRIME)s"s][ ]*)? )?(?P[EW])?)(?: %(SEP)s (?P (?P-?%(FLOAT)s)[ ]* (?Pkm|m|mi|ft|nm|nmi)))? \s*$ """ % UTIL_PATTERNS, re.X) def __new__(cls, latitude=None, longitude=None, altitude=None): single_arg = longitude is None and altitude is None if single_arg and not isinstance(latitude, util.NUMBER_TYPES): arg = latitude if arg is None: pass elif isinstance(arg, Point): return cls.from_point(arg) elif isinstance(arg, basestring): return cls.from_string(arg) else: try: seq = iter(arg) except TypeError: raise TypeError( "Failed to create Point instance from %r." % (arg,) ) else: return cls.from_sequence(seq) latitude = float(latitude or 0) if abs(latitude) > 90: latitude = ((latitude + 90) % 180) - 90 longitude = float(longitude or 0) if abs(longitude) > 180: longitude = ((longitude + 180) % 360) - 180 altitude = float(altitude or 0) self = super(Point, cls).__new__(cls) self.latitude = latitude self.longitude = longitude self.altitude = altitude return self def __getitem__(self, index): return (self.latitude, self.longitude, self.altitude)[index] def __setitem__(self, index, value): point = [self.latitude, self.longitude, self.altitude] point[index] = value self.latitude, self.longitude, self.altitude = point def __iter__(self): return iter((self.latitude, self.longitude, self.altitude)) def __repr__(self): return "Point(%r, %r, %r)" % ( self.latitude, self.longitude, self.altitude ) def format(self, altitude=None, deg_char='', min_char='m', sec_char='s'): latitude = "%s %s" % ( format.format_degrees(abs(self.latitude), symbols = {'deg': deg_char, 'arcmin': min_char, 'arcsec': sec_char}), self.latitude >= 0 and 'N' or 'S' ) longitude = "%s %s" % ( format.format_degrees(abs(self.longitude), symbols = {'deg': deg_char, 'arcmin': min_char, 'arcsec': sec_char}), self.longitude >= 0 and 'E' or 'W' ) coordinates = [latitude, longitude] if altitude is None: altitude = bool(self.altitude) if altitude: if not isinstance(altitude, basestring): altitude = 'km' coordinates.append(self.format_altitude(altitude)) return ", ".join(coordinates) def format_decimal(self, altitude=None): latitude = "%s" % self.latitude longitude = "%s" % self.longitude coordinates = [latitude, longitude] if altitude is None: altitude = bool(self.altitude) if altitude: if not isinstance(altitude, basestring): altitude = 'km' coordinates.append(self.format_altitude(altitude)) return ", ".join(coordinates) def format_altitude(self, unit='km'): return format.distance(self.altitude, unit) def __str__(self): return self.format() def __unicode__(self): return self.format( None, format.DEGREE, format.PRIME, format.DOUBLE_PRIME ) def __eq__(self, other): return tuple(self) == tuple(other) def __ne__(self, other): return tuple(self) != tuple(other) @classmethod def parse_degrees(cls, degrees, arcminutes, arcseconds, direction=None): negative = degrees < 0 or degrees.startswith('-') degrees = float(degrees or 0) arcminutes = float(arcminutes or 0) arcseconds = float(arcseconds or 0) if arcminutes or arcseconds: more = units.degrees(arcminutes=arcminutes, arcseconds=arcseconds) if negative: degrees -= more else: degrees += more if direction in [None, 'N', 'E']: return degrees elif direction in ['S', 'W']: return -degrees else: raise ValueError("Invalid direction! Should be one of [NSEW].") @classmethod def parse_altitude(cls, distance, unit): if distance is not None: distance = float(distance) CONVERTERS = { 'km': lambda d: d, 'm': lambda d: units.kilometers(meters=d), 'mi': lambda d: units.kilometers(miles=d), 'ft': lambda d: units.kilometers(feet=d), 'nm': lambda d: units.kilometers(nautical=d), 'nmi': lambda d: units.kilometers(nautical=d) } return CONVERTERS[unit](distance) else: return distance @classmethod def from_string(cls, string): """ Create and return a Point instance from a string containing latitude and longitude, and optionally, altitude. Latitude and longitude must be in degrees and may be in decimal form or indicate arcminutes and arcseconds (labeled with Unicode prime and double prime, ASCII quote and double quote or 'm' and 's'). The degree symbol is optional and may be included after the decimal places (in decimal form) and before the arcminutes and arcseconds otherwise. Coordinates given from south and west (indicated by S and W suffixes) will be converted to north and east by switching their signs. If no (or partial) cardinal directions are given, north and east are the assumed directions. Latitude and longitude must be separated by at least whitespace, a comma, or a semicolon (each with optional surrounding whitespace). Altitude, if supplied, must be a decimal number with given units. The following unit abbrevations (case-insensitive) are supported: km (kilometers) m (meters) mi (miles) ft (feet) nm, nmi (nautical miles) Some example strings the will work include: 41.5;-81.0 41.5,-81.0 41.5 -81.0 41.5 N -81.0 W -41.5 S;81.0 E 23 26m 22s N 23 27m 30s E 23 26' 22" N 23 27' 30" E """ match = re.match(cls.POINT_PATTERN, string) if match: latitude = cls.parse_degrees( match.group('latitude_degrees'), match.group('latitude_arcminutes'), match.group('latitude_arcseconds'), match.group('latitude_direction') ) longitude = cls.parse_degrees( match.group('longitude_degrees'), match.group('longitude_arcminutes'), match.group('longitude_arcseconds'), match.group('longitude_direction'), ) altitude = cls.parse_altitude( match.group('altitude_distance'), match.group('altitude_units') ) return cls(latitude, longitude, altitude) else: raise ValueError( "Failed to create Point instance from string: unknown format." ) @classmethod def from_sequence(cls, seq): """ Create and return a new Point instance from any iterable with 0 to 3 elements. The elements, if present, must be latitude, longitude, and altitude, respectively. """ args = tuple(islice(seq, 4)) return cls(*args) @classmethod def from_point(cls, point): """ Create and return a new Point instance from another Point instance. """ return cls(point.latitude, point.longitude, point.altitude) geopy-0.95.1/geopy/tests/0000755€¢Þ:€+8~0000000000012123101075021116 5ustar mtigasPROPUBLICA\Domain Users00000000000000geopy-0.95.1/geopy/tests/__init__.py0000644€¢Þ:€+8~0000000000012117720124023222 0ustar mtigasPROPUBLICA\Domain Users00000000000000geopy-0.95.1/geopy/tests/run_tests.py0000644€¢Þ:€+8~0000000140312117720124023521 0ustar mtigasPROPUBLICA\Domain Users00000000000000#!/usr/bin/env python import unittest import sys from geopy.tests.test_backends import get_suite as get_backend_suite from geopy.tests.test_gpx import get_suite as get_gpx_suite def all_tests(): # Test if BeautifulSoup is installed, since the microformat # parser relies on it. try: from BeautifulSoup import BeautifulSoup except ImportError: BeautifulSoup = None tests = [ get_backend_suite(), get_gpx_suite(), ] if BeautifulSoup: from test_microformats import get_suite as get_microformat_suite tests.append(get_microformat_suite()) return unittest.TestSuite(tests) if __name__ == '__main__': tests = all_tests() failures = unittest.TextTestRunner(verbosity=2).run(tests) geopy-0.95.1/geopy/tests/test_backends.py0000644€¢Þ:€+8~0000001216212117725341024316 0ustar mtigasPROPUBLICA\Domain Users00000000000000import unittest from urllib2 import URLError import socket socket.setdefaulttimeout(3.0) # Define some generic test functions that are common to all backends def _basic_address_test(self): address = '999 W. Riverside Ave., Spokane, WA 99201' try: clean_address, latlon = self.geocoder.geocode(address) except URLError as e: if "timed out" in str(e).lower(): raise unittest.SkipTest('geocoder service timed out') else: raise self.assertAlmostEqual(latlon[0], 47.658, delta=.002) self.assertAlmostEqual(latlon[1], -117.426, delta=.002) def _partial_address_test(self): address = '435 north michigan, chicago 60611' try: clean_address, latlon = self.geocoder.geocode(address) except URLError as e: if "timed out" in str(e).lower(): raise unittest.SkipTest('geocoder service timed out') else: raise self.assertAlmostEqual(latlon[0], 41.890, delta=.002) self.assertAlmostEqual(latlon[1], -87.624, delta=.002) def _intersection_test(self): address = 'e. 161st st & river ave, new york, ny' try: clean_address, latlon = self.geocoder.geocode(address) except URLError as e: if "timed out" in str(e).lower(): raise unittest.SkipTest('geocoder service timed out') else: raise self.assertAlmostEqual(latlon[0], 40.828, delta=.002) self.assertAlmostEqual(latlon[1], -73.926, delta=.002) def _placename_test(self): address = 'Mount St. Helens' try: # Since a place name search is significantly less accurate, # allow multiple results to come in. We'll check the top one. places = self.geocoder.geocode(address, exactly_one=False) except URLError as e: if "timed out" in str(e).lower(): raise unittest.SkipTest('geocoder service timed out') else: raise place = places[0] clean_address, latlon = place # And since this is a pretty fuzzy search, we'll only test to .02 self.assertAlmostEqual(latlon[0], 46.1912, delta=.02) self.assertAlmostEqual(latlon[1], -122.1944, delta=.02) # ========== # Define the test cases that actually perform the import and instantiation step class GoogleTestCase(unittest.TestCase): def setUp(self): from geopy.geocoders.google import Google self.geocoder = Google() class GoogleV3TestCase(unittest.TestCase): def setUp(self): from geopy.geocoders.googlev3 import GoogleV3 self.geocoder = GoogleV3() class BingTestCase(unittest.TestCase): def setUp(self): from geopy.geocoders.bing import Bing self.geocoder = Bing('Ao8kAepVCp_mQ583XgHg-rga2dwneQ4LtivmtuDj307vGjteiiqfI6ggjmx63wYR') class YahooTestCase(unittest.TestCase): def setUp(self): from geopy.geocoders.yahoo import Yahoo self.geocoder = Yahoo('IhDhBmjV34Es_uagpOkitrTdVbd71SFfJptjhE_MTV9kOpjrQ.TFWU.33viYp5_k') class DotUSTestCase(unittest.TestCase): def setUp(self): from geopy.geocoders.dot_us import GeocoderDotUS self.geocoder = GeocoderDotUS() class OpenMapQuestTestCase(unittest.TestCase): def setUp(self): from geopy.geocoders.openmapquest import OpenMapQuest self.geocoder = OpenMapQuest() # Does not do fuzzy address search. test_basic_address = _basic_address_test test_placename = _placename_test class MapQuestTestCase(unittest.TestCase): def setUp(self): from geopy.geocoders.mapquest import MapQuest self.geocoder = MapQuest('Dmjtd%7Clu612007nq%2C20%3Do5-50zah') # Does not do fuzzy address search. test_basic_address = _basic_address_test test_placename = _placename_test class GeoNamesTestCase(unittest.TestCase): def setUp(self): from geopy.geocoders.geonames import GeoNames self.geocoder = GeoNames() # Does not do any address searching. test_placename = _placename_test BASIC_TESTCASES = [GoogleTestCase, GoogleV3TestCase, BingTestCase, DotUSTestCase, YahooTestCase] # geonames does not actually test against addresses (just place names) #TESTCASES = [GoogleTestCase, BingTestCase, YahooTestCase, DotUSTestCase, GeoNamesTestCase] # ========== # Monkey patch the "generic" test functions into the testcases above for x in BASIC_TESTCASES: x.test_basic_address = _basic_address_test x.test_partial_address = _partial_address_test x.test_intersection = _intersection_test x.test_placename = _placename_test # ========== def get_suite(): test_methods = [ 'test_basic_address', 'test_partial_address', 'test_intersection', 'test_placename', ] tests = [] for tc in BASIC_TESTCASES: tests.extend(map(tc,test_methods)) tests.append(OpenMapQuestTestCase('test_basic_address')) tests.append(OpenMapQuestTestCase('test_placename')) tests.append(MapQuestTestCase('test_basic_address')) tests.append(MapQuestTestCase('test_placename')) tests.append(GeoNamesTestCase('test_placename')) return unittest.TestSuite(tests) if __name__ == '__main__': unittest.main() geopy-0.95.1/geopy/tests/test_distance.py0000644€¢Þ:€+8~0000001600412117720124024327 0ustar mtigasPROPUBLICA\Domain Users00000000000000import math from nose.tools import assert_raises, assert_almost_equal from geopy.point import Point from geopy.distance import (Distance, GreatCircleDistance, VincentyDistance, EARTH_RADIUS, ELLIPSOIDS) EARTH_CIRCUMFERENCE = 2 * math.pi * EARTH_RADIUS NORTH_POLE = Point(90, 0) SOUTH_POLE = Point(-90, 0) FIJI = Point(-16.1333333, 180.0) # Vunikondi, Fiji class CommonDistanceComputationCases: def test_zero_measure(self): self.cls( (40.753152999999998, -73.982275999999999), (40.753152999999998, -73.982275999999999) ) def test_should_have_length_when_only_given_length(self): distance = 1 assert self.cls(distance).kilometers == distance def test_should_have_zero_distance_for_coincident_points(self): assert self.cls((0, 0), (0, 0)).kilometers == 0 def test_should_have_nonzero_distance_for_distinct_points(self): assert self.cls((0, 0), (0, 1)).kilometers > 0 def test_max_longitude(self): distance = self.cls(kilometers=1.0) destination = distance.destination(FIJI, 45) assert_almost_equal(destination.longitude, -179.99338, 4) def test_should_compute_distance_for_trip_between_poles(self): distance = self.cls(SOUTH_POLE, NORTH_POLE) expected_distance = EARTH_CIRCUMFERENCE / 2 assert_almost_equal(distance.kilometers, expected_distance, -2) def test_should_compute_destination_for_trip_between_poles(self): distance = self.cls(EARTH_CIRCUMFERENCE / 2) destination = distance.destination(NORTH_POLE, 0) assert_almost_equal(destination.latitude, -90, 0) assert_almost_equal(destination.longitude, 0) def test_should_recognize_equivalence_of_pos_and_neg_180_longitude(self): distance = self.cls((0, 180), (0, -180)).kilometers assert_almost_equal(distance, 0) class CommonMathematicalOperatorCases: def test_should_be_able_to_add_distances(self): added = self.cls(1.0) + self.cls(1.0) assert_almost_equal(added.kilometers, 2.0) def test_should_not_allow_adding_with_objects_that_arent_distances(self): assert_raises(TypeError, lambda: self.cls(1.0) + 5) def test_should_be_able_to_negate_distances(self): distance = self.cls(1.0) assert_almost_equal(-(distance.kilometers), (-distance).kilometers) def test_should_be_able_to_subtract_distances(self): subtracted = self.cls(2.0) - self.cls(1.0) assert_almost_equal(subtracted.kilometers, 1) def test_should_be_able_to_multiply_distances_by_floats(self): assert_almost_equal((self.cls(2.0) * 2.0).kilometers, 4.0) def test_should_not_be_able_to_multiply_distances_by_distances(self): assert_raises(TypeError, lambda: self.cls(1.0) * self.cls(2.0)) def test_should_be_able_to_divide_distances_by_distances(self): ratio = self.cls(4.0) / self.cls(2.0) assert_almost_equal(ratio, 2.0) def test_should_be_able_to_divide_distances_by_floats(self): divided_distance = self.cls(4.0) / 2.0 assert_almost_equal(divided_distance.kilometers, 2.0) def test_should_be_able_to_take_absolute_value_of_distances(self): assert_almost_equal(abs(self.cls(-1.0)).kilometers, 1.0) def test_should_be_true_in_boolean_context_when_nonzero_length(self): assert self.cls(1.0) def test_should_be_false_in_boolean_context_when_zero_length(self): assert not self.cls(0) def test_should_get_consistent_results_for_distance_calculations(self): distance1, distance2 = [self.cls((0, 0), (0, 1)) for _ in range(2)] assert distance1.kilometers == distance2.kilometers class CommonConversionCases: def test_should_convert_to_kilometers(self): assert self.cls(1.0).kilometers == 1.0 def test_should_convert_to_kilometers_with_abbreviation(self): assert self.cls(1.0).km == 1.0 def test_should_convert_to_meters(self): assert self.cls(1.0).meters == 1000.0 def test_should_convert_to_meters_with_abbreviation(self): assert self.cls(1.0).m == 1000.0 def test_should_convert_to_miles(self): assert_almost_equal(self.cls(1.0).miles, 0.621371192) def test_should_convert_to_miles_with_abbreviation(self): assert_almost_equal(self.cls(1.0).mi, 0.621371192) def test_should_convert_to_feet(self): assert_almost_equal(self.cls(1.0).feet, 3280.8399, 4) def test_should_convert_to_feet_with_abbreviation(self): assert_almost_equal(self.cls(1.0).ft, 3280.8399, 4) def test_should_convert_to_nautical_miles(self): assert_almost_equal(self.cls(1.0).nautical, 0.539956803) def test_should_convert_to_nautical_miles_with_abbrevation(self): assert_almost_equal(self.cls(1.0).nm, 0.539956803) class CommonDistanceCases(CommonDistanceComputationCases, CommonMathematicalOperatorCases, CommonConversionCases): pass class TestWhenInstantiatingBaseDistanceClass: def test_should_not_be_able_to_give_multiple_points(self): assert_raises(NotImplementedError, lambda: Distance(1, 2, 3, 4)) class TestWhenComputingGreatCircleDistance(CommonDistanceCases): cls = GreatCircleDistance def test_should_compute_distance_for_half_trip_around_equator(self): distance_around_earth = self.cls((0, 0), (0, 180)).kilometers assert distance_around_earth == EARTH_CIRCUMFERENCE / 2 def test_should_compute_destination_for_half_trip_around_equator(self): distance = self.cls(EARTH_CIRCUMFERENCE / 2) destination = distance.destination((0, 0), 0) assert_almost_equal(destination.latitude, 0) assert_almost_equal(destination.longitude, 180) class TestWhenComputingVincentyDistance(CommonDistanceCases): cls = VincentyDistance def setup(self): self.original_ellipsoid = self.cls.ELLIPSOID def teardown(self): self.cls.ELLIPSOID = self.original_ellipsoid def test_should_not_converge_for_half_trip_around_equator(self): assert_raises(ValueError, self.cls, (0, 0), (0, 180)) def test_should_compute_destination_for_half_trip_around_equator(self): distance = self.cls(EARTH_CIRCUMFERENCE / 2) destination = distance.destination((0, 0), 0) assert_almost_equal(destination.latitude, 0, 0) assert_almost_equal(destination.longitude, -180, 0) def test_should_get_distinct_results_for_different_ellipsoids(self): results = [] for ellipsoid_name in ELLIPSOIDS.keys(): self.cls.ELLIPSOID = ELLIPSOIDS[ellipsoid_name] results.append(self.cls((0, 0), (0, 1))) assert not any(results[x].kilometers == results[y].kilometers for x in range(len(results)) for y in range(len(results)) if x != y) geopy-0.95.1/geopy/tests/test_geohash.py0000644€¢Þ:€+8~0000000257312117720124024161 0ustar mtigasPROPUBLICA\Domain Users00000000000000from geopy.geohash import Geohash class TestWhenConvertingKnownGeohashValues: # These known-good hashes were taken from geohash.org on 16 November 2008. all_four_quadrants = [ ('41.4997130', '-81.6937160', 'dpmuj4b3q7nq8'), # Cleveland ('19.0176560', '72.8561780', 'te7u1yh1zupbc'), # Mumbai ('-31.9554000', '115.8585900', 'qd66hqtwkcdjy'), # Perth ('-34.6117810', '-58.4173090', '69y7nejgf03k0'), # Buenos Aires ] edge_cases = [ ('-90', '0', 'h000'), ('90', '0', 'upbp'), ('0', '-180', '800000000'), ('0', '180', 'xbpbpbpbp'), ] known_hashes = all_four_quadrants + edge_cases def point_returns_geohash(self, latitude, longitude, expected_hash): geohash_length = len(expected_hash) hasher = Geohash(precision=geohash_length) geohash = hasher.encode(latitude, longitude) assert geohash == expected_hash def test_should_convert_points_to_hashes(self): for latitude, longitude, geohash in self.known_hashes: yield self.point_returns_geohash, latitude, longitude, geohash def test_should_provide_requested_precision(self): latitude, longitude, full_geohash = self.known_hashes[0] for precision in range(0, 14): geohash = full_geohash[:precision] yield self.point_returns_geohash, latitude, longitude, geohash geopy-0.95.1/geopy/tests/test_gpx.py0000644€¢Þ:€+8~0000000473212117720124023340 0ustar mtigasPROPUBLICA\Domain Users00000000000000#!/usr/bin/env python import unittest, os, logging from geopy import Point from geopy.parsers import gpx from datetime import datetime from geopy.parsers.iso8601 import TimeZone log = logging.getLogger('geopy.parsers.gpx') TEST_FILE = os.path.join( os.path.dirname(__file__), 'fells_loop.gpx') # From http://www.topografix.com/fells_loop.gpx class GPX(object): def test_version(self): self.assertTrue(self.GPXi.version == '1.1') def test_creator(self): self.assertTrue( self.GPXi.creator == 'ExpertGPS 1.1 - http://www.topografix.com') def test_route_names(self): names = list(self.GPXi.route_names) self.assertTrue(names == ['BELLEVUE (first three waypoints)', 'BELLEVUE']) def test_route_list(self): route = list(self.GPXi.get_waypoints( 'BELLEVUE (first three waypoints)')) self.assertTrue(route == [Point(42.430950, -71.107628, 23.469600), Point(42.431240, -71.109236, 26.561890), Point(42.434980, -71.109942, 45.307495)]) second_top_level_waypoint = list(self.GPXi.waypoints)[1] self.assertTrue(second_top_level_waypoint == Point(42.439227, -71.119689, 57.607200)) self.assertTrue(second_top_level_waypoint.timestamp == datetime(2001, 6, 2, 3, 26, 55, tzinfo = TimeZone('UTC'))) self.assertTrue(second_top_level_waypoint.name == '5067') self.assertTrue(second_top_level_waypoint.description == '5067') class GPXInitTestCase(GPX, unittest.TestCase): """ Tests GPX parser, when the parser is instantiated with a file object """ def setUp(self): self.f = open(TEST_FILE, 'r') self.GPXi = gpx.GPX(self.f) def tearDown(self): self.f.close() class GPXOpenerTestCase(GPX, unittest.TestCase): """ Tests GPX parser, when file is loaded via the .open() method """ def setUp(self): self.f = open(TEST_FILE, 'r') self.GPXi = gpx.GPX() self.GPXi.open(self.f) def tearDown(self): self.f.close() def get_suite(): test_methods = [ 'test_version', 'test_creator', 'test_route_names', 'test_route_list', ] tests = [] tests.extend(map(GPXInitTestCase,test_methods)) tests.extend(map(GPXOpenerTestCase,test_methods)) return unittest.TestSuite(tests) if __name__ == '__main__': unittest.main() geopy-0.95.1/geopy/tests/test_microformats.py0000644€¢Þ:€+8~0000001145412117720124025246 0ustar mtigasPROPUBLICA\Domain Users00000000000000#!/usr/bin/env python import unittest from geopy import format, Location, Point from geopy.parsers.html import GeoMicroformat from BeautifulSoup import BeautifulSoup class GeoMicroformatFound(object): def setUp(self): self.parser = GeoMicroformat() def test_one_str(self): locations = self.parser.find_all(self.MARKUP) self.assertTrue(len(locations) == 1) self._location_test(locations[0]) def test_multi_str(self): locations = self.parser.find_all(self.MARKUP * 3) self.assertTrue(len(locations) == 3) for i in range(3): self._location_test(locations[i]) def test_one_soup(self): if BeautifulSoup: locations = self.parser.find_all(BeautifulSoup(self.MARKUP)) self.assertTrue(len(locations) == 1) self._location_test(locations[0]) def test_multi_soup(self): if BeautifulSoup: locations = self.parser.find_all(BeautifulSoup(self.MARKUP * 3)) self.assertTrue(len(locations) == 3) for i in range(3): self._location_test(locations[i]) def _location_test(self, location): self.assertTrue(location.name == self.NAME) self.assertTrue(location.point == self.POINT) class GeoMicroformatNotFound(object): def setUp(self): self.parser = GeoMicroformat() def test_none_str(self): locations = self.parser.find_all(self.MARKUP) self.assertTrue(len(locations) == 0) def test_none_soup(self): if BeautifulSoup: locations = self.parser.find_all(BeautifulSoup(self.MARKUP)) self.assertTrue(len(locations) == 0) class GeoMicroformatFoundTest(GeoMicroformatFound, unittest.TestCase): MARKUP = """ 41.4924; -81.7239 """ NAME = "41.4924; -81.7239" POINT = Point(41.4924, -81.7239) class GeoMicroformatNotFoundTest(GeoMicroformatNotFound, unittest.TestCase): MARKUP = """ 41.4924; -81.7239 """ class FindAbbrLatLongTest(GeoMicroformatFoundTest): MARKUP = """ N 41.5, W 81.7 """ NAME = "N 41.5, W 81.7" class FindAbbrShorthandTest(GeoMicroformatFoundTest): MARKUP = """ N 41.5, W 81.7 """ NAME = "N 41.5, W 81.7" class NoShorthandNotFoundTest(GeoMicroformatNotFoundTest): def setUp(self): self.parser = GeoMicroformat(shorthand=False) MARKUP = """41.4924;-81.7239""" class NoShorthandFoundTest(GeoMicroformatFoundTest): def setUp(self): self.parser = GeoMicroformat(shorthand=False) MARKUP = """ 41.4924;-81.7239 41.4924; -81.7239 N 41.5, W 81.7 """ class FindNestedDefListTest(GeoMicroformatFoundTest): MARKUP = """
Geo
Latitude
12°20' 44" N
Longitude
123°27' 24" W
""" NAME = "Latitude 12%s20' 44\" N" \ " Longitude 123%s27' 24\" W" % (format.DEGREE, format.DEGREE) POINT = Point(12.3456789, -123.456789) def get_suite(): """ Returns a TestSuite containing all of the TestCases for microformats. If BeautifulSoup isn't installed, then tests against that library are skipped. """ geofound_test_methods = [ 'test_one_str', 'test_multi_str', ] geonotfound_test_methods = [ 'test_none_str', ] if BeautifulSoup: geofound_test_methods.extend(['test_one_soup','test_multi_soup',]) geonotfound_test_methods.append('test_none_soup') tests = [] tests.extend(map(GeoMicroformatFoundTest,geofound_test_methods)) tests.extend(map(FindAbbrLatLongTest,geofound_test_methods)) tests.extend(map(FindAbbrShorthandTest,geofound_test_methods)) tests.extend(map(NoShorthandFoundTest,geofound_test_methods)) tests.extend(map(FindNestedDefListTest,geofound_test_methods)) tests.extend(map(GeoMicroformatNotFoundTest,geonotfound_test_methods)) tests.extend(map(NoShorthandNotFoundTest,geonotfound_test_methods)) return unittest.TestSuite(tests) if __name__ == '__main__': unittest.main() geopy-0.95.1/geopy/units.py0000644€¢Þ:€+8~0000000440712117720124021502 0ustar mtigasPROPUBLICA\Domain Users00000000000000import math from geopy import util # Angles def degrees(radians=0, arcminutes=0, arcseconds=0): deg = 0. if radians: deg = math.degrees(radians) if arcminutes: deg += arcminutes / arcmin(degrees=1.) if arcseconds: deg += arcseconds / arcsec(degrees=1.) return deg def radians(degrees=0, arcminutes=0, arcseconds=0): if arcminutes: degrees += arcminutes / arcmin(degrees=1.) if arcseconds: degrees += arcseconds / arcsec(degrees=1.) return math.radians(degrees) def arcminutes(degrees=0, radians=0, arcseconds=0): if radians: degrees += math.degrees(radians) if arcseconds: degrees += arcseconds / arcsec(degrees=1.) return degrees * 60. def arcseconds(degrees=0, radians=0, arcminutes=0): if radians: degrees += math.degrees(radians) if arcminutes: degrees += arcminutes / arcmin(degrees=1.) return degrees * 3600. rad = radians arcmin = arcminutes arcsec = arcseconds # Lengths def kilometers(meters=0, miles=0, feet=0, nautical=0): km = 0. if meters: km += meters / 1000. if feet: miles += feet / ft(1.) if nautical: km += nautical / nm(1.) km += miles * 1.609344 return km def meters(kilometers=0, miles=0, feet=0, nautical=0): meters = 0. kilometers += km(nautical=nautical, miles=miles, feet=feet) meters += kilometers * 1000. return meters def miles(kilometers=0, meters=0, feet=0, nautical=0): mi = 0. if nautical: kilometers += nautical / nm(1.) if feet: mi += feet / ft(1.) if meters: kilometers += meters / 1000. mi += kilometers * 0.621371192 return mi def feet(kilometers=0, meters=0, miles=0, nautical=0): ft = 0. if nautical: kilometers += nautical / nm(1.) if meters: kilometers += meters / 1000. if kilometers: miles += mi(kilometers=kilometers) ft += miles * 5280 return ft def nautical(kilometers=0, meters=0, miles=0, feet=0): nm = 0. if feet: miles += feet / ft(1.) if miles: kilometers += km(miles=miles) if meters: kilometers += meters / 1000. nm += kilometers / 1.852 return nm km = kilometers m = meters mi = miles ft = feet nm = nauticalgeopy-0.95.1/geopy/util.py0000644€¢Þ:€+8~0000000535712117720124021322 0ustar mtigasPROPUBLICA\Domain Users00000000000000from sys import version_info import re import logging import htmlentitydefs import xml.dom.minidom from xml.parsers.expat import ExpatError try: from decimal import Decimal except ImportError: NUMBER_TYPES = (int, long, float) else: NUMBER_TYPES = (int, long, float, Decimal) class NullHandler(logging.Handler): def emit(self, record): pass logger = logging.getLogger('geopy') logger.addHandler(NullHandler()) def pairwise(seq): for i in range(0, len(seq) - 1): yield (seq[i], seq[i + 1]) def join_filter(sep, seq, pred=bool): return sep.join([unicode(i) for i in seq if pred(i)]) def get_encoding(page, contents=None): # TODO: clean up Py3k support if version_info < (3, 0): charset = page.headers.getparam("charset") or None else: charset = page.headers.get_param("charset") or None if charset: return charset if contents: try: return xml.dom.minidom.parseString(contents).encoding except ExpatError: pass def decode_page(page): contents = page.read() # HTTP 1.1 defines iso-8859-1 as the 'implied' encoding if none is given encoding = get_encoding(page, contents) or 'iso-8859-1' # TODO: clean up Py3k support if version_info < (3, 0): return unicode(contents, encoding=encoding).encode('utf-8') else: return str(contents, encoding=encoding) def get_first_text(node, tag_names, strip=None): if isinstance(tag_names, basestring): tag_names = [tag_names] if node: while tag_names: nodes = node.getElementsByTagName(tag_names.pop(0)) if nodes: child = nodes[0].firstChild return child and child.nodeValue.strip(strip) def join_filter(sep, seq, pred=bool): return sep.join([unicode(i) for i in seq if pred(i)]) import re, htmlentitydefs def unescape(text): """ Removes HTML or XML character references and entities from a text string. """ def fixup(m): text = m.group(0) if text[:2] == "&#": # character reference try: if text[:3] == "&#x": return unichr(int(text[3:-1], 16)) else: return unichr(int(text[2:-1])) except ValueError: pass else: # named entity try: text = unichr(htmlentitydefs.name2codepoint[text[1:-1]]) except KeyError: pass return text # leave as is return re.sub("&#?\w+;", fixup, text) try: reversed except NameError: def reversed(seq): i = len(seq) while i > 0: i -= 1 yield seq[i] else: reversed = reversed geopy-0.95.1/geopy.egg-info/0000755€¢Þ:€+8~0000000000012123101075021446 5ustar mtigasPROPUBLICA\Domain Users00000000000000geopy-0.95.1/geopy.egg-info/dependency_links.txt0000644€¢Þ:€+8~0000000000112123101075025514 0ustar mtigasPROPUBLICA\Domain Users00000000000000 geopy-0.95.1/geopy.egg-info/PKG-INFO0000644€¢Þ:€+8~0000000155412123101074022547 0ustar mtigasPROPUBLICA\Domain Users00000000000000Metadata-Version: 1.1 Name: geopy Version: 0.95.1 Summary: Python Geocoding Toolbox Home-page: http://code.google.com/p/geopy/ Author: GeoPy Project / Mike Tigas Author-email: mike@tig.as License: MIT Download-URL: http://code.google.com/p/geopy/downloads/list Description: UNKNOWN Keywords: geocode geocoding gis geographical maps earth distance Platform: UNKNOWN Classifier: Development Status :: 5 - Production/Stable Classifier: Intended Audience :: Developers Classifier: Intended Audience :: Science/Research Classifier: License :: OSI Approved :: MIT License Classifier: Operating System :: OS Independent Classifier: Programming Language :: Python Classifier: Topic :: Scientific/Engineering :: GIS Classifier: Topic :: Software Development :: Libraries :: Python Modules Classifier: Programming Language :: Python :: 2 Classifier: Programming Language :: Python :: 3 geopy-0.95.1/geopy.egg-info/SOURCES.txt0000644€¢Þ:€+8~0000000173212123101075023335 0ustar mtigasPROPUBLICA\Domain Users00000000000000LICENSE MANIFEST.in RELEASES setup.cfg setup.py geopy/__init__.py geopy/distance.py geopy/format.py geopy/geohash.py geopy/location.py geopy/point.py geopy/units.py geopy/util.py geopy.egg-info/PKG-INFO geopy.egg-info/SOURCES.txt geopy.egg-info/dependency_links.txt geopy.egg-info/top_level.txt geopy/geocoders/__init__.py geopy/geocoders/base.py geopy/geocoders/bing.py geopy/geocoders/dot_us.py geopy/geocoders/geonames.py geopy/geocoders/google.py geopy/geocoders/googlev3.py geopy/geocoders/mapquest.py geopy/geocoders/openmapquest.py geopy/geocoders/virtual_earth.py geopy/geocoders/wiki_gis.py geopy/geocoders/wiki_semantic.py geopy/geocoders/yahoo.py geopy/parsers/__init__.py geopy/parsers/base.py geopy/parsers/gpx.py geopy/parsers/html.py geopy/parsers/iso8601.py geopy/parsers/rdf.py geopy/tests/__init__.py geopy/tests/run_tests.py geopy/tests/test_backends.py geopy/tests/test_distance.py geopy/tests/test_geohash.py geopy/tests/test_gpx.py geopy/tests/test_microformats.pygeopy-0.95.1/geopy.egg-info/top_level.txt0000644€¢Þ:€+8~0000000000612123101075024174 0ustar mtigasPROPUBLICA\Domain Users00000000000000geopy geopy-0.95.1/LICENSE0000644€¢Þ:€+8~0000000220712117720124017644 0ustar mtigasPROPUBLICA\Domain Users00000000000000Copyright (c) 2006-2010 Brian Beck Copyright (c) 2010-2012 GeoPy Project and individual contributors. All rights reserved. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. geopy-0.95.1/MANIFEST.in0000644€¢Þ:€+8~0000000006512117720124020375 0ustar mtigasPROPUBLICA\Domain Users00000000000000include LICENSE include MANIFEST.in include RELEASES geopy-0.95.1/PKG-INFO0000644€¢Þ:€+8~0000000155412123101075017733 0ustar mtigasPROPUBLICA\Domain Users00000000000000Metadata-Version: 1.1 Name: geopy Version: 0.95.1 Summary: Python Geocoding Toolbox Home-page: http://code.google.com/p/geopy/ Author: GeoPy Project / Mike Tigas Author-email: mike@tig.as License: MIT Download-URL: http://code.google.com/p/geopy/downloads/list Description: UNKNOWN Keywords: geocode geocoding gis geographical maps earth distance Platform: UNKNOWN Classifier: Development Status :: 5 - Production/Stable Classifier: Intended Audience :: Developers Classifier: Intended Audience :: Science/Research Classifier: License :: OSI Approved :: MIT License Classifier: Operating System :: OS Independent Classifier: Programming Language :: Python Classifier: Topic :: Scientific/Engineering :: GIS Classifier: Topic :: Software Development :: Libraries :: Python Modules Classifier: Programming Language :: Python :: 2 Classifier: Programming Language :: Python :: 3 geopy-0.95.1/RELEASES0000644€¢Þ:€+8~0000000670512123101004017757 0ustar mtigasPROPUBLICA\Domain Users000000000000000.95.1 - March 22, 2013 ========== FIXED: Fix #12, where `DeprecationWarning` was showing for GoogleV2 even if it wasn't being used (due to `geopy.geocoders` importing it). Contributed by Dave Arter. CHANGED: `GoogleV3.geocode` "address" kwarg renamed to "string" to match `Google.geocode` to make updating easier. FIXED: Geocoders now properly handle Unicode objects as input (previously would fail on non-ASCII characters due to wanting UTF-8 strings). 0.95 - March 12, 2013 ========== ADDED: Google Geocoding API V3 support. Contributed by Jordan Bouvier (jbouvier). "google.Google()" should be replaced by "googlev3.GoogleV3()", with no `api_key`. Please see http://goo.gl/somDT for valid arguments. UPDATED: setup.py updated to now automatically support Python 3+ (via 2to3 auto-compile option). Contributed by Feanil Patel. 0.94.2 - March 12, 2012 ========== ADDED: MANIFEST.in so that LICENSE file gets included in dist packages (per req by Debian Python Module Team) UPDATED: Yahoo geocoder uses new PlaceFinder API instead of outdated MapsService V1 API. 0.94.1 - March 24, 2011 ========== ADDED: Test suite includes geocoding tests for the Google, Bing, Yahoo, GeocoderDotUS, and GeoNames geocoders. CHANGED: `output_format` is deprecated in backends that used it. FIXED: Bing geocoder now works properly. Updated to use the JSON return method rather than XML. `output_format` has always been ignored and is now deprecated. FIXED: GeocoderDotUS now works properly. Updated to use more compact CSV return method rather than XMLRPC. CHANGED: Yahoo geocoder now uses the "old" tuple return format (address, (lat, lon)) rather than the undocumented Location() object, for API consistency. (Object return values with rich data will be implemented in a future release.) FIXED: Issue 40. Fixed "print" statement in Bing backend. No more print statements remain. FIXED: Issue 39. In addition to checking for system `json` and `simplejson`, geopy now looks for a system-installed `django` (which bundles a copy of simplejson). FIXED: Issue 45. Implement __cmp__ on Distance so that distance objects may be compared against one another. CHANGED: Added __repr__ and __str__ to Distance ADDED: Issue 46. Geocoder backend for MapQuest's OpenMapQuest API, contributed by Shashwat Anand. 0.94 - March 7, 2010 ==================== ADDED: Partial test suite can now be run via "setup.py test" FIXED: Issue 5. Converted "print" statements to logger calls to allow compatibility with WSGI. FIXED: Issue 16. Google geocoder backend now throws more descriptive exceptions on certain failure statuses. FIXED: Issue 18. Add simplejson to install_requires for setup. Use native (Python 2.6+/3.0+) json module if available. FIXED: Issue 21 and Issue 25. Distance calculations for values beyond 180/-180 and 90/-90 now wrap instead of raising an error. FIXED: Issue 22. Fixed string representation of Point objects so that they don't throw an exception. FIXED: Issue 23. Fixed GreatCircleDistance ValueErrors due to floating point precision on extremely close points. Changes between 0.93 (October 8, 2006) and February 15, 2009 ============================================================ See https://github.com/mtigas/geopy/compare/0451a051...ffebd5f3 geopy-0.95.1/setup.cfg0000644€¢Þ:€+8~0000000007312123101075020452 0ustar mtigasPROPUBLICA\Domain Users00000000000000[egg_info] tag_svn_revision = 0 tag_date = 0 tag_build = geopy-0.95.1/setup.py0000644€¢Þ:€+8~0000000324112123077215020353 0ustar mtigasPROPUBLICA\Domain Users00000000000000import os from setuptools import setup, find_packages from pkg_resources import resource_string install_requires = [] # Test if we have built-in JSON - Python 2.6+, 3.0+. # Older Python versions require simplejson. # Alternatively, if Django is installed, plug into the django # copy of simplejson. try: import json except ImportError: try: import simplejson except ImportError: try: from django.utils import simplejson except: install_requires.append('simplejson') # note: not automated since py3k cannot import geopy.get_version at # install-time (since 2to3 has not yet run) version = "0.95.1" setup(name='geopy', version=version, description='Python Geocoding Toolbox', author='GeoPy Project / Mike Tigas', author_email='mike@tig.as', # subject to change url='http://code.google.com/p/geopy/', download_url='http://code.google.com/p/geopy/downloads/list', packages=find_packages(), install_requires=install_requires, test_suite = "geopy.tests.run_tests.all_tests", license='MIT', keywords='geocode geocoding gis geographical maps earth distance', classifiers=["Development Status :: 5 - Production/Stable", "Intended Audience :: Developers", "Intended Audience :: Science/Research", "License :: OSI Approved :: MIT License", "Operating System :: OS Independent", "Programming Language :: Python", "Topic :: Scientific/Engineering :: GIS", "Topic :: Software Development :: Libraries :: Python Modules", "Programming Language :: Python :: 2", "Programming Language :: Python :: 3", ], use_2to3=True, )