Skip to content

Commit aa95981

Browse files
committed
Merge pull request #11 from maxmind/greg/new-dbs
Greg/new dbs
2 parents e133e5d + b062bfa commit aa95981

File tree

5 files changed

+275
-42
lines changed

5 files changed

+275
-42
lines changed

README.rst

Lines changed: 77 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -97,9 +97,32 @@ Web Service Example
9797
>>> response.location.longitude
9898
-93.2323
9999
100+
Web Service Client Exceptions
101+
-----------------------------
102+
103+
For details on the possible errors returned by the web service itself, see
104+
http://dev.maxmind.com/geoip/geoip2/web-services for the GeoIP2 web service
105+
docs.
106+
107+
If the web service returns an explicit error document, this is thrown as a
108+
``AddressNotFoundError``, ``AuthenticationError``, ``InvalidRequestError``, or
109+
``OutOfQueriesError`` as appropriate. These all subclass ``GeoIP2Error``.
110+
111+
If some other sort of error occurs, this is thrown as an ``HTTPError``. This
112+
is thrown when some sort of unanticipated error occurs, such as the web
113+
service returning a 500 or an invalid error document. If the web service
114+
returns any status code besides 200, 4xx, or 5xx, this also becomes an
115+
``HTTPError``.
116+
117+
Finally, if the web service returns a 200 but the body is invalid, the client
118+
throws a ``GeoIP2Error``.
119+
100120
Database Example
101121
-------------------
102122

123+
City Database
124+
^^^^^^^^^^^^^
125+
103126
.. code-block:: pycon
104127
105128
>>> import geoip2.database
@@ -134,26 +157,65 @@ Database Example
134157
44.9733
135158
>>> response.location.longitude
136159
-93.2323
160+
>>> reader.close()
137161
138-
Web Service Client Exceptions
139-
-----------------------------
162+
Connection-Type Database
163+
^^^^^^^^^^^^^^^^^^^^^^^^
140164

141-
For details on the possible errors returned by the web service itself, see
142-
http://dev.maxmind.com/geoip/geoip2/web-services for the GeoIP2 web service
143-
docs.
165+
>>> import geoip2.database
166+
>>>
167+
>>> # This creates a Reader object. You should use the same object
168+
>>> # across multiple requests as creation of it is expensive.
169+
>>> reader = geoip2.database.Reader('/path/to/GeoIP2-Connection-Type.mmdb')
170+
>>>
171+
>>> response = reader.connection_type('128.101.101.101')
172+
>>>
173+
>>> response.connection_type
174+
'Corporate'
175+
>>> response.ip_address
176+
'128.101.101.101'
177+
>>> reader.close()
144178

145-
If the web service returns an explicit error document, this is thrown as a
146-
``AddressNotFoundError``, ``AuthenticationError``, ``InvalidRequestError``, or
147-
``OutOfQueriesError`` as appropriate. These all subclass ``GeoIP2Error``.
148179

149-
If some other sort of error occurs, this is thrown as an ``HTTPError``. This
150-
is thrown when some sort of unanticipated error occurs, such as the web
151-
service returning a 500 or an invalid error document. If the web service
152-
returns any status code besides 200, 4xx, or 5xx, this also becomes an
153-
``HTTPError``.
180+
Domain Database
181+
^^^^^^^^^^^^^^^
154182

155-
Finally, if the web service returns a 200 but the body is invalid, the client
156-
throws a ``GeoIP2Error``.
183+
>>> import geoip2.database
184+
>>>
185+
>>> # This creates a Reader object. You should use the same object
186+
>>> # across multiple requests as creation of it is expensive.
187+
>>> reader = geoip2.database.Reader('/path/to/GeoIP2-Domain.mmdb')
188+
>>>
189+
>>> response = reader.domain('128.101.101.101')
190+
>>>
191+
>>> response.domain
192+
'umn.edu'
193+
>>> response.ip_address
194+
'128.101.101.101'
195+
>>> reader.close()
196+
197+
ISP Database
198+
^^^^^^^^^^^^
199+
200+
>>> import geoip2.database
201+
>>>
202+
>>> # This creates a Reader object. You should use the same object
203+
>>> # across multiple requests as creation of it is expensive.
204+
>>> reader = geoip2.database.Reader('/path/to/GeoIP2-ISP.mmdb')
205+
>>>
206+
>>> response = reader.isp('1.128.0.0')
207+
>>>
208+
>>> response.autonomous_system_number
209+
1221
210+
>>> response.autonomous_system_organization
211+
'Telstra Pty Ltd'
212+
>>> response.isp
213+
'Telstra Internet'
214+
>>> response.organization
215+
'Telstra Internet'
216+
>>> response.ip_address
217+
'128.101.101.101'
218+
>>> reader.close()
157219

158220
Database Reader Exceptions
159221
--------------------------

geoip2/database.py

Lines changed: 49 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,7 @@ class Reader(object):
1717
Instances of this class provide a reader for the GeoIP2 database format.
1818
IP addresses can be looked up using the ``country`` and ``city`` methods.
1919
We also provide ``city_isp_org`` and ``omni`` methods to ease
20-
compatibility with the web service client, although we may offer the
21-
ability to specify additional databases to replicate these web services in
22-
the future (e.g., the ISP/Org database).
20+
compatibility with the web service client.
2321
2422
Usage
2523
-----
@@ -49,11 +47,9 @@ def __init__(self, filename, locales=None):
4947
self._locales = locales
5048

5149
def country(self, ip_address):
52-
"""Get the Country record object for the IP address
50+
"""Get the Country object for the IP address
5351
54-
:param ip_address: IPv4 or IPv6 address as a string. If no address
55-
is provided, the address that the web service is called from will
56-
be used.
52+
:param ip_address: IPv4 or IPv6 address as a string.
5753
5854
:returns: :py:class:`geoip2.models.Country` object
5955
@@ -62,23 +58,20 @@ def country(self, ip_address):
6258
return self._model_for(geoip2.models.Country, ip_address)
6359

6460
def city(self, ip_address):
65-
"""Get the City record object for the IP address
61+
"""Get the City object for the IP address
6662
67-
:param ip_address: IPv4 or IPv6 address as a string. If no address
68-
is provided, the address that the web service is called from will
69-
be used.
63+
:param ip_address: IPv4 or IPv6 address as a string.
7064
7165
:returns: :py:class:`geoip2.models.City` object
7266
7367
"""
7468
return self._model_for(geoip2.models.City, ip_address)
7569

7670
def city_isp_org(self, ip_address):
77-
"""Get the CityISPOrg record object for the IP address
71+
"""Get the CityISPOrg object for the IP address
7872
7973
:param ip_address: IPv4 or IPv6 address as a string. If no address
80-
is provided, the address that the web service is called from will
81-
be used.
74+
is provided.
8275
8376
:returns: :py:class:`geoip2.models.CityISPOrg` object
8477
@@ -87,25 +80,62 @@ def city_isp_org(self, ip_address):
8780
return self._model_for(geoip2.models.CityISPOrg, ip_address)
8881

8982
def omni(self, ip_address):
90-
"""Get the Omni record object for the IP address
83+
"""Get the Omni object for the IP address
9184
92-
:param ip_address: IPv4 or IPv6 address as a string. If no address
93-
is provided, the address that the web service is called from will
94-
be used.
85+
:param ip_address: IPv4 or IPv6 address as a string.
9586
9687
:returns: :py:class:`geoip2.models.Omni` object
9788
9889
"""
9990
return self._model_for(geoip2.models.Omni, ip_address)
10091

101-
def _model_for(self, model_class, ip_address):
92+
def connection_type(self, ip_address):
93+
"""Get the ConnectionType object for the IP address
94+
95+
:param ip_address: IPv4 or IPv6 address as a string.
96+
97+
:returns: :py:class:`geoip2.models.ConnectionType` object
98+
99+
"""
100+
return self._flat_model_for(geoip2.models.ConnectionType, ip_address)
101+
102+
def domain(self, ip_address):
103+
"""Get the Domain object for the IP address
104+
105+
:param ip_address: IPv4 or IPv6 address as a string.
106+
107+
:returns: :py:class:`geoip2.models.Domain` object
108+
109+
"""
110+
return self._flat_model_for(geoip2.models.Domain, ip_address)
111+
112+
def isp(self, ip_address):
113+
"""Get the ISP object for the IP address
114+
115+
:param ip_address: IPv4 or IPv6 address as a string.
116+
117+
:returns: :py:class:`geoip2.models.ISP` object
118+
119+
"""
120+
return self._flat_model_for(geoip2.models.ISP, ip_address)
121+
122+
def _get(self, ip_address):
102123
record = self._db_reader.get(ip_address)
103124
if record is None:
104125
raise geoip2.errors.AddressNotFoundError(
105126
"The address %s is not in the database." % ip_address)
127+
return record
128+
129+
def _model_for(self, model_class, ip_address):
130+
record = self._get(ip_address)
106131
record.setdefault('traits', {})['ip_address'] = ip_address
107132
return model_class(record, locales=self._locales)
108133

134+
def _flat_model_for(self, model_class, ip_address):
135+
record = self._get(ip_address)
136+
record['ip_address'] = ip_address
137+
return model_class(record)
138+
109139
def close(self):
110140
"""Closes the GeoIP2 database"""
111141

geoip2/models.py

Lines changed: 112 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,9 @@
1616

1717
class Country(object):
1818

19-
"""Model class for the GeoIP2 Country end point
19+
"""Model class for the GeoIP2 Country
2020
21-
This class provides the following methods, each of which returns a record
22-
object.
21+
This class provides the following attributes:
2322
2423
.. attribute:: continent
2524
@@ -93,7 +92,7 @@ def __init__(self, raw_response, locales=None):
9392

9493
class City(Country):
9594

96-
"""Model class for the GeoIP2 Precision City end point
95+
"""Model class for the GeoIP2 Precision City
9796
9897
.. attribute:: city
9998
@@ -171,7 +170,7 @@ def __init__(self, raw_response, locales=None):
171170

172171
class CityISPOrg(City):
173172

174-
"""Model class for the GeoIP2 Precision City/ISP/Org end point
173+
"""Model class for the GeoIP2 Precision City/ISP/Org
175174
176175
.. attribute:: city
177176
@@ -237,7 +236,7 @@ class CityISPOrg(City):
237236

238237
class Omni(CityISPOrg):
239238

240-
"""Model class for the GeoIP2 Precision Omni end point
239+
"""Model class for the GeoIP2 Precision Omni
241240
242241
.. attribute:: city
243242
@@ -299,3 +298,110 @@ class Omni(CityISPOrg):
299298
:type: :py:class:`geoip2.records.Traits`
300299
301300
"""
301+
302+
303+
class ConnectionType(object):
304+
305+
"""Model class for the GeoIP2 Connection-Type
306+
307+
This class provides the following attribute:
308+
309+
.. attribute:: connection_type
310+
311+
The connection type may take the following values:
312+
313+
- Dialup
314+
- Cable/DSL
315+
- Corporate
316+
- Cellular
317+
318+
Additional values may be added in the future.
319+
320+
:type: unicode
321+
322+
.. attribute:: ip_address
323+
324+
The IP address used in the lookup.
325+
326+
:type: unicode
327+
"""
328+
329+
def __init__(self, raw):
330+
self.connection_type = raw.get('connection_type')
331+
self.ip_address = raw.get('ip_address')
332+
self.raw = raw
333+
334+
335+
class Domain(object):
336+
337+
"""Model class for the GeoIP2 Domain
338+
339+
This class provides the following attribute:
340+
341+
.. attribute:: domain
342+
343+
The domain associated with the IP address.
344+
345+
:type: unicode
346+
347+
.. attribute:: ip_address
348+
349+
The IP address used in the lookup.
350+
351+
:type: unicode
352+
353+
"""
354+
355+
def __init__(self, raw):
356+
self.domain = raw.get('domain')
357+
self.ip_address = raw.get('ip_address')
358+
self.raw = raw
359+
360+
361+
class ISP(object):
362+
363+
"""Model class for the GeoIP2 ISP
364+
365+
This class provides the following attribute:
366+
367+
.. attribute:: autonomous_system_number
368+
369+
The autonomous system number associated with the IP address.
370+
371+
:type: int
372+
373+
.. attribute:: autonomous_system_organization
374+
375+
The organization associated with the registered autonomous system number
376+
for the IP address.
377+
378+
:type: unicode
379+
380+
.. attribute:: isp
381+
382+
The name of the ISP associated with the IP address.
383+
384+
:type: unicode
385+
386+
.. attribute:: organization
387+
388+
The name of the organization associated with the IP address.
389+
390+
:type: unicode
391+
392+
.. attribute:: ip_address
393+
394+
The IP address used in the lookup.
395+
396+
:type: unicode
397+
"""
398+
399+
# pylint:disable=too-many-arguments
400+
def __init__(self, raw):
401+
self.autonomous_system_number = raw.get('autonomous_system_number')
402+
self.autonomous_system_organization = raw.get(
403+
'autonomous_system_organization')
404+
self.isp = raw.get('isp')
405+
self.organization = raw.get('organization')
406+
self.ip_address = raw.get('ip_address')
407+
self.raw = raw

0 commit comments

Comments
 (0)