Commit eeaaa314 by Jennifer Ennis

merged pull request to fix #7

parent 536fbc2b
""" """
Pure Python GeoIP API. The API is based off of U{MaxMind's C-based Python API<http://www.maxmind.com/app/python>}, Pure Python GeoIP API. The API is based off of U{MaxMind's C-based Python API<http://www.maxmind.com/app/python>},
but the code itself is based on the U{pure PHP5 API<http://pear.php.net/package/Net_GeoIP/>} but the code itself is based on the U{pure PHP5 API<http://pear.php.net/package/Net_GeoIP/>}
by Jim Winstead and Hans Lellelid. by Jim Winstead and Hans Lellelid.
It is mostly a drop-in replacement, except the It is mostly a drop-in replacement, except the
C{new} and C{open} methods are gone. You should instantiate the L{GeoIP} class yourself: C{new} and C{open} methods are gone. You should instantiate the L{GeoIP} class yourself:
C{gi = GeoIP('/path/to/GeoIP.dat', pygeoip.MEMORY_CACHE)} C{gi = GeoIP('/path/to/GeoIP.dat', pygeoip.MEMORY_CACHE)}
@author: Jennifer Ennis <zaylea at gmail dot com> @author: Jennifer Ennis <zaylea at gmail dot com>
@license: @license:
Copyright(C) 2004 MaxMind LLC Copyright(C) 2004 MaxMind LLC
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/lgpl.txt>. along with this program. If not, see <http://www.gnu.org/licenses/lgpl.txt>.
""" """
from __future__ import with_statement, absolute_import, division from __future__ import with_statement, absolute_import, division
import os import os
import math import math
import socket import socket
import mmap import mmap
import gzip import gzip
import codecs import codecs
from StringIO import StringIO
from . import const
from .util import ip2long from . import const
from .timezone import time_zone_by_country_and_region from .util import ip2long
from .timezone import time_zone_by_country_and_region
import six
import six
MMAP_CACHE = const.MMAP_CACHE
MEMORY_CACHE = const.MEMORY_CACHE MMAP_CACHE = const.MMAP_CACHE
STANDARD = const.STANDARD MEMORY_CACHE = const.MEMORY_CACHE
STANDARD = const.STANDARD
class GeoIPError(Exception):
pass class GeoIPError(Exception):
pass
class GeoIPMetaclass(type):
class GeoIPMetaclass(type):
def __new__(cls, *args, **kwargs):
""" def __new__(cls, *args, **kwargs):
Singleton method to gets an instance without reparsing the db. Unique """
instances are instantiated based on the filename of the db. Flags are Singleton method to gets an instance without reparsing the db. Unique
ignored for this, i.e. if you initialize one with STANDARD flag (default) instances are instantiated based on the filename of the db. Flags are
and then try later to initialize with MEMORY_CACHE, it will still ignored for this, i.e. if you initialize one with STANDARD flag (default)
return the STANDARD one. and then try later to initialize with MEMORY_CACHE, it will still
""" return the STANDARD one.
"""
if not hasattr(cls, '_instances'):
cls._instances = {} if not hasattr(cls, '_instances'):
cls._instances = {}
if len(args) > 0:
filename = args[0] if len(args) > 0:
elif 'filename' in kwargs: filename = args[0]
filename = kwargs['filename'] elif 'filename' in kwargs:
filename = kwargs['filename']
if not filename in cls._instances:
cls._instances[filename] = type.__new__(cls, *args, **kwargs) if not filename in cls._instances:
cls._instances[filename] = type.__new__(cls, *args, **kwargs)
return cls._instances[filename]
return cls._instances[filename]
GeoIPBase = GeoIPMetaclass('GeoIPBase', (object,), {})
GeoIPBase = GeoIPMetaclass('GeoIPBase', (object,), {})
class GeoIP(GeoIPBase):
class GeoIP(GeoIPBase):
def __init__(self, filename, flags=0):
""" def __init__(self, filename, flags=0):
Initialize the class. """
Initialize the class.
@param filename: path to a geoip database. If MEMORY_CACHE is used,
the file can be gzipped. @param filename: path to a geoip database. If MEMORY_CACHE is used,
@type filename: str the file can be gzipped.
@param flags: flags that affect how the database is processed. @type filename: str
Currently the only supported flags are STANDARD (the default), @param flags: flags that affect how the database is processed.
MEMORY_CACHE (preload the whole file into memory), and Currently the only supported flags are STANDARD (the default),
MMAP_CACHE (access the file via mmap). MEMORY_CACHE (preload the whole file into memory), and
@type flags: int MMAP_CACHE (access the file via mmap).
""" @type flags: int
self._filename = filename """
self._flags = flags self._filename = filename
self._flags = flags
if self._flags & const.MMAP_CACHE:
with open(filename, 'rb') as f: if self._flags & const.MMAP_CACHE:
self._filehandle = mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_READ) with open(filename, 'rb') as f:
self._filehandle = mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_READ)
elif self._flags & const.MEMORY_CACHE:
self._filehandle = gzip.open(filename, 'rb') elif self._flags & const.MEMORY_CACHE:
self._memoryBuffer = self._filehandle.read() if filename.endswith('.gz'):
opener = gzip.open
else: else:
self._filehandle = codecs.open(filename, 'rb','latin_1') opener = open
self._setup_segments() with opener(filename, 'rb') as f:
self._memoryBuffer = f.read()
def _setup_segments(self): self._filehandle = StringIO(self._memoryBuffer)
""" else:
Parses the database file to determine what kind of database is being used and setup self._filehandle = codecs.open(filename, 'rb','latin_1')
segment sizes and start points that will be used by the seek*() methods later.
""" self._setup_segments()
self._databaseType = const.COUNTRY_EDITION
self._recordLength = const.STANDARD_RECORD_LENGTH def _setup_segments(self):
"""
filepos = self._filehandle.tell() Parses the database file to determine what kind of database is being used and setup
self._filehandle.seek(-3, os.SEEK_END) segment sizes and start points that will be used by the seek*() methods later.
"""
for i in range(const.STRUCTURE_INFO_MAX_SIZE): self._databaseType = const.COUNTRY_EDITION
delim = self._filehandle.read(3) self._recordLength = const.STANDARD_RECORD_LENGTH
if delim == six.u(chr(255) * 3): filepos = self._filehandle.tell()
self._databaseType = ord(self._filehandle.read(1)) self._filehandle.seek(-3, os.SEEK_END)
if (self._databaseType >= 106): for i in range(const.STRUCTURE_INFO_MAX_SIZE):
# backwards compatibility with databases from April 2003 and earlier delim = self._filehandle.read(3)
self._databaseType -= 105
if delim == six.u(chr(255) * 3):
if self._databaseType == const.REGION_EDITION_REV0: self._databaseType = ord(self._filehandle.read(1))
self._databaseSegments = const.STATE_BEGIN_REV0
if (self._databaseType >= 106):
elif self._databaseType == const.REGION_EDITION_REV1: # backwards compatibility with databases from April 2003 and earlier
self._databaseSegments = const.STATE_BEGIN_REV1 self._databaseType -= 105
elif self._databaseType in (const.CITY_EDITION_REV0, if self._databaseType == const.REGION_EDITION_REV0:
const.CITY_EDITION_REV1, self._databaseSegments = const.STATE_BEGIN_REV0
const.ORG_EDITION,
const.ISP_EDITION, elif self._databaseType == const.REGION_EDITION_REV1:
const.ASNUM_EDITION): self._databaseSegments = const.STATE_BEGIN_REV1
self._databaseSegments = 0
buf = self._filehandle.read(const.SEGMENT_RECORD_LENGTH) elif self._databaseType in (const.CITY_EDITION_REV0,
const.CITY_EDITION_REV1,
for j in range(const.SEGMENT_RECORD_LENGTH): const.ORG_EDITION,
self._databaseSegments += (ord(buf[j]) << (j * 8)) const.ISP_EDITION,
const.ASNUM_EDITION):
if self._databaseType in (const.ORG_EDITION, const.ISP_EDITION): self._databaseSegments = 0
self._recordLength = const.ORG_RECORD_LENGTH buf = self._filehandle.read(const.SEGMENT_RECORD_LENGTH)
break for j in range(const.SEGMENT_RECORD_LENGTH):
else: self._databaseSegments += (ord(buf[j]) << (j * 8))
self._filehandle.seek(-4, os.SEEK_CUR)
if self._databaseType in (const.ORG_EDITION, const.ISP_EDITION):
if self._databaseType == const.COUNTRY_EDITION: self._recordLength = const.ORG_RECORD_LENGTH
self._databaseSegments = const.COUNTRY_BEGIN
break
self._filehandle.seek(filepos, os.SEEK_SET) else:
self._filehandle.seek(-4, os.SEEK_CUR)
def _lookup_country_id(self, addr):
""" if self._databaseType == const.COUNTRY_EDITION:
Get the country index. self._databaseSegments = const.COUNTRY_BEGIN
This method is called by the _lookupCountryCode and _lookupCountryName self._filehandle.seek(filepos, os.SEEK_SET)
methods. It looks up the index ('id') for the country which is the key
for the code and name. def _lookup_country_id(self, addr):
"""
@param addr: The IP address Get the country index.
@type addr: str
@return: network byte order 32-bit integer This method is called by the _lookupCountryCode and _lookupCountryName
@rtype: int methods. It looks up the index ('id') for the country which is the key
""" for the code and name.
ipnum = ip2long(addr) @param addr: The IP address
@type addr: str
if not ipnum: @return: network byte order 32-bit integer
raise ValueError("Invalid IP address: %s" % addr) @rtype: int
"""
if self._databaseType != const.COUNTRY_EDITION:
raise GeoIPError('Invalid database type; country_* methods expect '\ ipnum = ip2long(addr)
'Country database')
if not ipnum:
return self._seek_country(ipnum) - const.COUNTRY_BEGIN raise ValueError("Invalid IP address: %s" % addr)
def _seek_country(self, ipnum): if self._databaseType != const.COUNTRY_EDITION:
""" raise GeoIPError('Invalid database type; country_* methods expect '\
Using the record length and appropriate start points, seek to the 'Country database')
country that corresponds to the converted IP address integer.
return self._seek_country(ipnum) - const.COUNTRY_BEGIN
@param ipnum: result of ip2long conversion
@type ipnum: int def _seek_country(self, ipnum):
@return: offset of start of record """
@rtype: int Using the record length and appropriate start points, seek to the
""" country that corresponds to the converted IP address integer.
offset = 0
@param ipnum: result of ip2long conversion
for depth in range(31, -1, -1): @type ipnum: int
@return: offset of start of record
if self._flags & const.MEMORY_CACHE: @rtype: int
startIndex = 2 * self._recordLength * offset """
length = 2 * self._recordLength offset = 0
endIndex = startIndex + length
buf = self._memoryBuffer[startIndex:endIndex] for depth in range(31, -1, -1):
else:
self._filehandle.seek(2 * self._recordLength * offset, os.SEEK_SET) if self._flags & const.MEMORY_CACHE:
buf = self._filehandle.read(2 * self._recordLength) startIndex = 2 * self._recordLength * offset
length = 2 * self._recordLength
x = [0,0] endIndex = startIndex + length
buf = self._memoryBuffer[startIndex:endIndex]
for i in range(2): else:
for j in range(self._recordLength): self._filehandle.seek(2 * self._recordLength * offset, os.SEEK_SET)
x[i] += ord(buf[self._recordLength * i + j]) << (j * 8) buf = self._filehandle.read(2 * self._recordLength)
if ipnum & (1 << depth): x = [0,0]
if x[1] >= self._databaseSegments: for i in range(2):
return x[1] for j in range(self._recordLength):
x[i] += ord(buf[self._recordLength * i + j]) << (j * 8)
offset = x[1]
if ipnum & (1 << depth):
else:
if x[1] >= self._databaseSegments:
if x[0] >= self._databaseSegments: return x[1]
return x[0]
offset = x[1]
offset = x[0]
else:
raise Exception('Error traversing database - perhaps it is corrupt?') if x[0] >= self._databaseSegments:
return x[0]
def _get_org(self, ipnum):
""" offset = x[0]
Seek and return organization (or ISP) name for converted IP addr.
@param ipnum: Converted IP address
@type ipnum: int raise Exception('Error traversing database - perhaps it is corrupt?')
@return: org/isp name
@rtype: str def _get_org(self, ipnum):
""" """
Seek and return organization (or ISP) name for converted IP addr.
seek_org = self._seek_country(ipnum) @param ipnum: Converted IP address
if seek_org == self._databaseSegments: @type ipnum: int
return None @return: org/isp name
@rtype: str
record_pointer = seek_org + (2 * self._recordLength - 1) * self._databaseSegments """
self._filehandle.seek(record_pointer, os.SEEK_SET) seek_org = self._seek_country(ipnum)
if seek_org == self._databaseSegments:
org_buf = self._filehandle.read(const.MAX_ORG_RECORD_LENGTH) return None
return org_buf[:org_buf.index(chr(0))] record_pointer = seek_org + (2 * self._recordLength - 1) * self._databaseSegments
def _get_region(self, ipnum): self._filehandle.seek(record_pointer, os.SEEK_SET)
"""
Seek and return the region info (dict containing country_code and region_name). org_buf = self._filehandle.read(const.MAX_ORG_RECORD_LENGTH)
@param ipnum: converted IP address return org_buf[:org_buf.index(chr(0))]
@type ipnum: int
@return: dict containing country_code and region_name def _get_region(self, ipnum):
@rtype: dict """
""" Seek and return the region info (dict containing country_code and region_name).
country_code = ''
region = '' @param ipnum: converted IP address
@type ipnum: int
if self._databaseType == const.REGION_EDITION_REV0: @return: dict containing country_code and region_name
seek_country = self._seek_country(ipnum) @rtype: dict
seek_region = seek_country - const.STATE_BEGIN_REV0 """
if seek_region >= 1000: country_code = ''
country_code = 'US' region = ''
region = ''.join([chr((seek_region // 1000) // 26 + 65), chr((seek_region // 1000) % 26 + 65)])
else: if self._databaseType == const.REGION_EDITION_REV0:
country_code = const.COUNTRY_CODES[seek_region] seek_country = self._seek_country(ipnum)
region = '' seek_region = seek_country - const.STATE_BEGIN_REV0
elif self._databaseType == const.REGION_EDITION_REV1: if seek_region >= 1000:
seek_country = self._seek_country(ipnum) country_code = 'US'
seek_region = seek_country - const.STATE_BEGIN_REV1 region = ''.join([chr((seek_region // 1000) // 26 + 65), chr((seek_region // 1000) % 26 + 65)])
if seek_region < const.US_OFFSET: else:
country_code = ''; country_code = const.COUNTRY_CODES[seek_region]
region = '' region = ''
elif seek_region < const.CANADA_OFFSET: elif self._databaseType == const.REGION_EDITION_REV1:
country_code = 'US' seek_country = self._seek_country(ipnum)
region = ''.join([chr((seek_region - const.US_OFFSET) // 26 + 65), chr((seek_region - const.US_OFFSET) % 26 + 65)]) seek_region = seek_country - const.STATE_BEGIN_REV1
elif seek_region < const.WORLD_OFFSET: if seek_region < const.US_OFFSET:
country_code = 'CA' country_code = '';
region = ''.join([chr((seek_region - const.CANADA_OFFSET) // 26 + 65), chr((seek_region - const.CANADA_OFFSET) % 26 + 65)]) region = ''
else: elif seek_region < const.CANADA_OFFSET:
i = (seek_region - const.WORLD_OFFSET) // const.FIPS_RANGE country_code = 'US'
if i < len(const.COUNTRY_CODES): region = ''.join([chr((seek_region - const.US_OFFSET) // 26 + 65), chr((seek_region - const.US_OFFSET) % 26 + 65)])
#country_code = const.COUNTRY_CODES[(seek_region - const.WORLD_OFFSET) // const.FIPS_RANGE] elif seek_region < const.WORLD_OFFSET:
country_code = const.COUNTRY_CODES[i] country_code = 'CA'
else: region = ''.join([chr((seek_region - const.CANADA_OFFSET) // 26 + 65), chr((seek_region - const.CANADA_OFFSET) % 26 + 65)])
country_code = '' else:
region = '' i = (seek_region - const.WORLD_OFFSET) // const.FIPS_RANGE
if i < len(const.COUNTRY_CODES):
elif self._databaseType in (const.CITY_EDITION_REV0, const.CITY_EDITION_REV1): #country_code = const.COUNTRY_CODES[(seek_region - const.WORLD_OFFSET) // const.FIPS_RANGE]
rec = self._get_record(ipnum) country_code = const.COUNTRY_CODES[i]
country_code = rec['country_code'] if 'country_code' in rec else '' else:
region = rec['region_name'] if 'region_name' in rec else '' country_code = ''
region = ''
return {'country_code' : country_code, 'region_name' : region }
elif self._databaseType in (const.CITY_EDITION_REV0, const.CITY_EDITION_REV1):
def _get_record(self, ipnum): rec = self._get_record(ipnum)
""" country_code = rec['country_code'] if 'country_code' in rec else ''
Populate location dict for converted IP. region = rec['region_name'] if 'region_name' in rec else ''
@param ipnum: converted IP address return {'country_code' : country_code, 'region_name' : region }
@type ipnum: int
@return: dict with country_code, country_code3, country_name, def _get_record(self, ipnum):
region, city, postal_code, latitude, longitude, """
dma_code, metro_code, area_code, region_name, time_zone Populate location dict for converted IP.
@rtype: dict
""" @param ipnum: converted IP address
seek_country = self._seek_country(ipnum) @type ipnum: int
if seek_country == self._databaseSegments: @return: dict with country_code, country_code3, country_name,
return None region, city, postal_code, latitude, longitude,
dma_code, metro_code, area_code, region_name, time_zone
record_pointer = seek_country + (2 * self._recordLength - 1) * self._databaseSegments @rtype: dict
"""
self._filehandle.seek(record_pointer, os.SEEK_SET) seek_country = self._seek_country(ipnum)
record_buf = self._filehandle.read(const.FULL_RECORD_LENGTH) if seek_country == self._databaseSegments:
return None
record = {}
record_pointer = seek_country + (2 * self._recordLength - 1) * self._databaseSegments
record_buf_pos = 0
char = ord(record_buf[record_buf_pos]) self._filehandle.seek(record_pointer, os.SEEK_SET)
#char = record_buf[record_buf_pos] if six.PY3 else ord(record_buf[record_buf_pos]) record_buf = self._filehandle.read(const.FULL_RECORD_LENGTH)
record['country_code'] = const.COUNTRY_CODES[char]
record['country_code3'] = const.COUNTRY_CODES3[char] record = {}
record['country_name'] = const.COUNTRY_NAMES[char]
record_buf_pos += 1 record_buf_pos = 0
str_length = 0 char = ord(record_buf[record_buf_pos])
#char = record_buf[record_buf_pos] if six.PY3 else ord(record_buf[record_buf_pos])
# get region record['country_code'] = const.COUNTRY_CODES[char]
char = ord(record_buf[record_buf_pos+str_length]) record['country_code3'] = const.COUNTRY_CODES3[char]
while (char != 0): record['country_name'] = const.COUNTRY_NAMES[char]
str_length += 1 record_buf_pos += 1
char = ord(record_buf[record_buf_pos+str_length]) str_length = 0
if str_length > 0: # get region
record['region_name'] = record_buf[record_buf_pos:record_buf_pos+str_length] char = ord(record_buf[record_buf_pos+str_length])
while (char != 0):
record_buf_pos += str_length + 1 str_length += 1
str_length = 0 char = ord(record_buf[record_buf_pos+str_length])
# get city if str_length > 0:
char = ord(record_buf[record_buf_pos+str_length]) record['region_name'] = record_buf[record_buf_pos:record_buf_pos+str_length]
while (char != 0):
str_length += 1 record_buf_pos += str_length + 1
char = ord(record_buf[record_buf_pos+str_length]) str_length = 0
if str_length > 0: # get city
record['city'] = record_buf[record_buf_pos:record_buf_pos+str_length] char = ord(record_buf[record_buf_pos+str_length])
else: while (char != 0):
record['city'] = '' str_length += 1
char = ord(record_buf[record_buf_pos+str_length])
record_buf_pos += str_length + 1
str_length = 0 if str_length > 0:
record['city'] = record_buf[record_buf_pos:record_buf_pos+str_length]
# get the postal code else:
char = ord(record_buf[record_buf_pos+str_length]) record['city'] = ''
while (char != 0):
str_length += 1 record_buf_pos += str_length + 1
char = ord(record_buf[record_buf_pos+str_length]) str_length = 0
if str_length > 0: # get the postal code
record['postal_code'] = record_buf[record_buf_pos:record_buf_pos+str_length] char = ord(record_buf[record_buf_pos+str_length])
else: while (char != 0):
record['postal_code'] = None str_length += 1
char = ord(record_buf[record_buf_pos+str_length])
record_buf_pos += str_length + 1
str_length = 0 if str_length > 0:
record['postal_code'] = record_buf[record_buf_pos:record_buf_pos+str_length]
latitude = 0 else:
longitude = 0 record['postal_code'] = None
for j in range(3):
char = ord(record_buf[record_buf_pos]) record_buf_pos += str_length + 1
record_buf_pos += 1 str_length = 0
latitude += (char << (j * 8))
latitude = 0
record['latitude'] = (latitude/10000.0) - 180.0 longitude = 0
for j in range(3):
for j in range(3): char = ord(record_buf[record_buf_pos])
char = ord(record_buf[record_buf_pos]) record_buf_pos += 1
record_buf_pos += 1 latitude += (char << (j * 8))
longitude += (char << (j * 8))
record['latitude'] = (latitude/10000.0) - 180.0
record['longitude'] = (longitude/10000.0) - 180.0
for j in range(3):
if self._databaseType == const.CITY_EDITION_REV1: char = ord(record_buf[record_buf_pos])
dmaarea_combo = 0 record_buf_pos += 1
if record['country_code'] == 'US': longitude += (char << (j * 8))
for j in range(3):
char = ord(record_buf[record_buf_pos]) record['longitude'] = (longitude/10000.0) - 180.0
record_buf_pos += 1
dmaarea_combo += (char << (j*8)) if self._databaseType == const.CITY_EDITION_REV1:
dmaarea_combo = 0
record['dma_code'] = int(math.floor(dmaarea_combo/1000)) if record['country_code'] == 'US':
record['area_code'] = dmaarea_combo%1000 for j in range(3):
else: char = ord(record_buf[record_buf_pos])
record['dma_code'] = 0 record_buf_pos += 1
record['area_code'] = 0 dmaarea_combo += (char << (j*8))
if 'dma_code' in record and record['dma_code'] in const.DMA_MAP: record['dma_code'] = int(math.floor(dmaarea_combo/1000))
record['metro_code'] = const.DMA_MAP[record['dma_code']] record['area_code'] = dmaarea_combo%1000
else: else:
record['metro_code'] = '' record['dma_code'] = 0
record['area_code'] = 0
if 'country_code' in record:
record['time_zone'] = time_zone_by_country_and_region( if 'dma_code' in record and record['dma_code'] in const.DMA_MAP:
record['country_code'], record.get('region_name')) or '' record['metro_code'] = const.DMA_MAP[record['dma_code']]
else: else:
record['time_zone'] = '' record['metro_code'] = ''
return record if 'country_code' in record:
record['time_zone'] = time_zone_by_country_and_region(
def country_code_by_addr(self, addr): record['country_code'], record.get('region_name')) or ''
""" else:
Returns 2-letter country code (e.g. 'US') for specified IP address. record['time_zone'] = ''
Use this method if you have a Country, Region, or City database.
return record
@param addr: IP address
@type addr: str def country_code_by_addr(self, addr):
@return: 2-letter country code """
@rtype: str Returns 2-letter country code (e.g. 'US') for specified IP address.
""" Use this method if you have a Country, Region, or City database.
try:
if self._databaseType == const.COUNTRY_EDITION: @param addr: IP address
country_id = self._lookup_country_id(addr) @type addr: str
return const.COUNTRY_CODES[country_id] @return: 2-letter country code
elif self._databaseType in (const.REGION_EDITION_REV0, const.REGION_EDITION_REV1, @rtype: str
const.CITY_EDITION_REV0, const.CITY_EDITION_REV1): """
return self.region_by_addr(addr)['country_code'] try:
else: if self._databaseType == const.COUNTRY_EDITION:
raise GeoIPError('Invalid database type; country_* methods expect '\ country_id = self._lookup_country_id(addr)
'Country, City, or Region database') return const.COUNTRY_CODES[country_id]
elif self._databaseType in (const.REGION_EDITION_REV0, const.REGION_EDITION_REV1,
except ValueError: const.CITY_EDITION_REV0, const.CITY_EDITION_REV1):
raise GeoIPError('*_by_addr methods only accept IP addresses. Use *_by_name for hostnames. (Address: %s)' % addr) return self.region_by_addr(addr)['country_code']
else:
def country_code_by_name(self, hostname): raise GeoIPError('Invalid database type; country_* methods expect '\
""" 'Country, City, or Region database')
Returns 2-letter country code (e.g. 'US') for specified hostname.
Use this method if you have a Country, Region, or City database. except ValueError:
raise GeoIPError('*_by_addr methods only accept IP addresses. Use *_by_name for hostnames. (Address: %s)' % addr)
@param hostname: host name
@type hostname: str def country_code_by_name(self, hostname):
@return: 2-letter country code """
@rtype: str Returns 2-letter country code (e.g. 'US') for specified hostname.
""" Use this method if you have a Country, Region, or City database.
addr = socket.gethostbyname(hostname)
@param hostname: host name
return self.country_code_by_addr(addr) @type hostname: str
@return: 2-letter country code
def country_name_by_addr(self, addr): @rtype: str
""" """
Returns full country name for specified IP address. addr = socket.gethostbyname(hostname)
Use this method if you have a Country or City database.
return self.country_code_by_addr(addr)
@param addr: IP address
@type addr: str def country_name_by_addr(self, addr):
@return: country name """
@rtype: str Returns full country name for specified IP address.
""" Use this method if you have a Country or City database.
try:
if self._databaseType == const.COUNTRY_EDITION: @param addr: IP address
country_id = self._lookup_country_id(addr) @type addr: str
return const.COUNTRY_NAMES[country_id] @return: country name
elif self._databaseType in (const.CITY_EDITION_REV0, const.CITY_EDITION_REV1): @rtype: str
return self.record_by_addr(addr)['country_name'] """
else: try:
raise GeoIPError('Invalid database type; country_* methods expect '\ if self._databaseType == const.COUNTRY_EDITION:
'Country or City database') country_id = self._lookup_country_id(addr)
except ValueError: return const.COUNTRY_NAMES[country_id]
raise GeoIPError('*_by_addr methods only accept IP addresses. Use *_by_name for hostnames. (Address: %s)' % addr) elif self._databaseType in (const.CITY_EDITION_REV0, const.CITY_EDITION_REV1):
return self.record_by_addr(addr)['country_name']
def country_name_by_name(self, hostname): else:
""" raise GeoIPError('Invalid database type; country_* methods expect '\
Returns full country name for specified hostname. 'Country or City database')
Use this method if you have a Country database. except ValueError:
raise GeoIPError('*_by_addr methods only accept IP addresses. Use *_by_name for hostnames. (Address: %s)' % addr)
@param hostname: host name
@type hostname: str def country_name_by_name(self, hostname):
@return: country name """
@rtype: str Returns full country name for specified hostname.
""" Use this method if you have a Country database.
addr = socket.gethostbyname(hostname)
return self.country_name_by_addr(addr) @param hostname: host name
@type hostname: str
def org_by_addr(self, addr): @return: country name
""" @rtype: str
Lookup the organization (or ISP) for given IP address. """
Use this method if you have an Organization/ISP database. addr = socket.gethostbyname(hostname)
return self.country_name_by_addr(addr)
@param addr: IP address
@type addr: str def org_by_addr(self, addr):
@return: organization or ISP name """
@rtype: str Lookup the organization (or ISP) for given IP address.
""" Use this method if you have an Organization/ISP database.
try:
ipnum = ip2long(addr) @param addr: IP address
@type addr: str
if not ipnum: @return: organization or ISP name
raise ValueError("Invalid IP address: %s" % addr) @rtype: str
"""
if self._databaseType not in (const.ORG_EDITION, const.ISP_EDITION, const.ASNUM_EDITION): try:
raise GeoIPError('Invalid database type; org_* methods expect '\ ipnum = ip2long(addr)
'Org/ISP database')
if not ipnum:
return self._get_org(ipnum) raise ValueError("Invalid IP address: %s" % addr)
except ValueError:
raise GeoIPError('*_by_addr methods only accept IP addresses. Use *_by_name for hostnames. (Address: %s)' % addr) if self._databaseType not in (const.ORG_EDITION, const.ISP_EDITION, const.ASNUM_EDITION):
raise GeoIPError('Invalid database type; org_* methods expect '\
def org_by_name(self, hostname): 'Org/ISP database')
"""
Lookup the organization (or ISP) for hostname. return self._get_org(ipnum)
Use this method if you have an Organization/ISP database. except ValueError:
raise GeoIPError('*_by_addr methods only accept IP addresses. Use *_by_name for hostnames. (Address: %s)' % addr)
@param hostname: host name
@type hostname: str def org_by_name(self, hostname):
@return: organization or ISP name """
@rtype: str Lookup the organization (or ISP) for hostname.
""" Use this method if you have an Organization/ISP database.
addr = socket.gethostbyname(hostname)
@param hostname: host name
return self.org_by_addr(addr) @type hostname: str
@return: organization or ISP name
def record_by_addr(self, addr): @rtype: str
""" """
Look up the record for a given IP address. addr = socket.gethostbyname(hostname)
Use this method if you have a City database.
return self.org_by_addr(addr)
@param addr: IP address
@type addr: str def record_by_addr(self, addr):
@return: dict with country_code, country_code3, country_name, """
region, city, postal_code, latitude, longitude, Look up the record for a given IP address.
dma_code, metro_code, area_code, region_name, time_zone Use this method if you have a City database.
@rtype: dict
""" @param addr: IP address
try: @type addr: str
ipnum = ip2long(addr) @return: dict with country_code, country_code3, country_name,
region, city, postal_code, latitude, longitude,
if not ipnum: dma_code, metro_code, area_code, region_name, time_zone
raise ValueError("Invalid IP address: %s" % addr) @rtype: dict
"""
if not self._databaseType in (const.CITY_EDITION_REV0, const.CITY_EDITION_REV1): try:
raise GeoIPError('Invalid database type; record_* methods expect City database') ipnum = ip2long(addr)
return self._get_record(ipnum) if not ipnum:
except ValueError: raise ValueError("Invalid IP address: %s" % addr)
raise GeoIPError('*_by_addr methods only accept IP addresses. Use *_by_name for hostnames. (Address: %s)' % addr)
if not self._databaseType in (const.CITY_EDITION_REV0, const.CITY_EDITION_REV1):
def record_by_name(self, hostname): raise GeoIPError('Invalid database type; record_* methods expect City database')
"""
Look up the record for a given hostname. return self._get_record(ipnum)
Use this method if you have a City database. except ValueError:
raise GeoIPError('*_by_addr methods only accept IP addresses. Use *_by_name for hostnames. (Address: %s)' % addr)
@param hostname: host name
@type hostname: str def record_by_name(self, hostname):
@return: dict with country_code, country_code3, country_name, """
region, city, postal_code, latitude, longitude, Look up the record for a given hostname.
dma_code, metro_code, area_code, region_name, time_zone Use this method if you have a City database.
@rtype: dict
""" @param hostname: host name
addr = socket.gethostbyname(hostname) @type hostname: str
@return: dict with country_code, country_code3, country_name,
return self.record_by_addr(addr) region, city, postal_code, latitude, longitude,
dma_code, metro_code, area_code, region_name, time_zone
def region_by_addr(self, addr): @rtype: dict
""" """
Lookup the region for given IP address. addr = socket.gethostbyname(hostname)
Use this method if you have a Region database.
return self.record_by_addr(addr)
@param addr: IP address
@type addr: str def region_by_addr(self, addr):
@return: dict containing country_code, region, """
and region_name Lookup the region for given IP address.
@rtype: dict Use this method if you have a Region database.
"""
try: @param addr: IP address
ipnum = ip2long(addr) @type addr: str
@return: dict containing country_code, region,
if not ipnum: and region_name
raise ValueError("Invalid IP address: %s" % addr) @rtype: dict
"""
if not self._databaseType in (const.REGION_EDITION_REV0, const.REGION_EDITION_REV1, try:
const.CITY_EDITION_REV0, const.CITY_EDITION_REV1): ipnum = ip2long(addr)
raise GeoIPError('Invalid database type; region_* methods expect '\
'Region or City database') if not ipnum:
raise ValueError("Invalid IP address: %s" % addr)
return self._get_region(ipnum)
except ValueError: if not self._databaseType in (const.REGION_EDITION_REV0, const.REGION_EDITION_REV1,
raise GeoIPError('*_by_addr methods only accept IP addresses. Use *_by_name for hostnames. (Address: %s)' % addr) const.CITY_EDITION_REV0, const.CITY_EDITION_REV1):
raise GeoIPError('Invalid database type; region_* methods expect '\
def region_by_name(self, hostname): 'Region or City database')
"""
Lookup the region for given hostname. return self._get_region(ipnum)
Use this method if you have a Region database. except ValueError:
raise GeoIPError('*_by_addr methods only accept IP addresses. Use *_by_name for hostnames. (Address: %s)' % addr)
@param hostname: host name
@type hostname: str def region_by_name(self, hostname):
@return: dict containing country_code, region, """
and region_name Lookup the region for given hostname.
@rtype: dict Use this method if you have a Region database.
"""
addr = socket.gethostbyname(hostname) @param hostname: host name
return self.region_by_addr(addr) @type hostname: str
@return: dict containing country_code, region,
def time_zone_by_addr(self, addr): and region_name
""" @rtype: dict
Look up the time zone for a given IP address. """
Use this method if you have a Region or City database. addr = socket.gethostbyname(hostname)
return self.region_by_addr(addr)
@param hostname: IP address
@type hostname: str def time_zone_by_addr(self, addr):
@return: Time zone """
@rtype: str Look up the time zone for a given IP address.
""" Use this method if you have a Region or City database.
try:
ipnum = ip2long(addr) @param hostname: IP address
@type hostname: str
if not ipnum: @return: Time zone
raise ValueError("Invalid IP address: %s" % addr) @rtype: str
"""
if not self._databaseType in (const.REGION_EDITION_REV0, const.REGION_EDITION_REV1, try:
const.CITY_EDITION_REV0, const.CITY_EDITION_REV1): ipnum = ip2long(addr)
raise GeoIPError('Invalid database type; region_* methods expect '\
'Region or City database') if not ipnum:
raise ValueError("Invalid IP address: %s" % addr)
return self._get_record(ipnum)['time_zone']
except ValueError: if not self._databaseType in (const.REGION_EDITION_REV0, const.REGION_EDITION_REV1,
raise GeoIPError('*_by_addr methods only accept IP addresses. Use *_by_name for hostnames. (Address: %s)' % addr) const.CITY_EDITION_REV0, const.CITY_EDITION_REV1):
raise GeoIPError('Invalid database type; region_* methods expect '\
def time_zone_by_name(self, hostname): 'Region or City database')
"""
Look up the time zone for a given hostname. return self._get_record(ipnum)['time_zone']
Use this method if you have a Region or City database. except ValueError:
raise GeoIPError('*_by_addr methods only accept IP addresses. Use *_by_name for hostnames. (Address: %s)' % addr)
@param hostname: host name
@type hostname: str def time_zone_by_name(self, hostname):
@return: Time zone """
@rtype: str Look up the time zone for a given hostname.
""" Use this method if you have a Region or City database.
addr = socket.gethostbyname(hostname)
return self.time_zone_by_addr(addr) @param hostname: host name
@type hostname: str
@return: Time zone
@rtype: str
"""
addr = socket.gethostbyname(hostname)
return self.time_zone_by_addr(addr)
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment