Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
P
pygeoip
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
OpenEdx
pygeoip
Commits
eeaaa314
Commit
eeaaa314
authored
May 25, 2012
by
Jennifer Ennis
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
merged pull request to fix #7
parent
536fbc2b
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
647 additions
and
641 deletions
+647
-641
pygeoip/__init__.py
+647
-641
No files found.
pygeoip/__init__.py
View file @
eeaaa314
"""
"""
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
)
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment