Skip to content

Commit 1a73c00

Browse files
authored
Merge pull request #91 from maxmind/greg/async-http
Add async web request support. Closes #56
2 parents 02c196e + 8f6785b commit 1a73c00

File tree

7 files changed

+616
-342
lines changed

7 files changed

+616
-342
lines changed

.travis.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ before_install:
2626
- "if [[ $RUN_SNYK && $SNYK_TOKEN ]]; then sudo apt-get install -y nodejs; npm install -g snyk; fi"
2727
install:
2828
- pip install -r requirements.txt
29-
- pip install requests_mock coveralls
29+
- pip install mocket coveralls
3030
- |
3131
if [[ $RUN_LINTER ]]; then
3232
pip install --upgrade pylint black mypy

HISTORY.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,18 @@ History
88

99
* IMPORTANT: Python 2.7 and 3.5 support has been dropped. Python 3.6 or greater
1010
is required.
11+
* Asyncio support has been added for web service requests. To make async
12+
requests, use ``geoip.webservice.AsyncClient``.
13+
* ``geoip.webservice.Client`` now provides a ``close()`` method and associated
14+
context managers to be used in ``with`` statements.
1115
* Type hints have been added.
1216
* The attributes ``postal_code`` and ``postal_confidence`` have been removed
1317
from ``geoip2.record.Location``. These would previously always be ``None``.
1418
* ``user_id`` is no longer supported as a named argument for the constructor
1519
on ``geoip2.webservice.Client``. Use ``account_id`` or a positional
1620
parameter instead.
21+
* For both ``Client`` and ``AsyncClient`` requests, the default timeout is
22+
now 60 seconds.
1723

1824
3.0.0 (2019-12-20)
1925
++++++++++++++++++

README.rst

Lines changed: 117 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,8 @@ each of which represents part of the data returned by the web service.
5757

5858
If the request fails, the client class throws an exception.
5959

60-
Web Service Example
61-
-------------------
60+
Sync Web Service Example
61+
------------------------
6262

6363
.. code-block:: pycon
6464
@@ -67,37 +67,82 @@ Web Service Example
6767
>>> # This creates a Client object that can be reused across requests.
6868
>>> # Replace "42" with your account ID and "license_key" with your license
6969
>>> # key.
70-
>>> client = geoip2.webservice.Client(42, 'license_key')
70+
>>> with geoip2.webservice.Client(42, 'license_key') as client:
71+
>>>
72+
>>> # Replace "insights" with the method corresponding to the web service
73+
>>> # that you are using, e.g., "country", "city".
74+
>>> response = client.insights('203.0.113.0')
75+
>>>
76+
>>> response.country.iso_code
77+
'US'
78+
>>> response.country.name
79+
'United States'
80+
>>> response.country.names['zh-CN']
81+
u'美国'
82+
>>>
83+
>>> response.subdivisions.most_specific.name
84+
'Minnesota'
85+
>>> response.subdivisions.most_specific.iso_code
86+
'MN'
87+
>>>
88+
>>> response.city.name
89+
'Minneapolis'
90+
>>>
91+
>>> response.postal.code
92+
'55455'
93+
>>>
94+
>>> response.location.latitude
95+
44.9733
96+
>>> response.location.longitude
97+
-93.2323
98+
>>>
99+
>>> response.traits.network
100+
IPv4Network('203.0.113.0/32')
101+
102+
Async Web Service Example
103+
------------------------
104+
105+
.. code-block:: pycon
106+
107+
>>> import geoip2.webservice
108+
>>>
109+
>>> # This creates an AsyncClient object that can be reused across
110+
>>> # requests on the running event loop. If you are using multiple event
111+
>>> # loops, you must ensure the object is not used on another loop.
112+
>>> #
113+
>>> # Replace "42" with your account ID and "license_key" with your license
114+
>>> # key.
115+
>>> async with geoip2.webservice.AsyncClient(42, 'license_key') as client:
71116
>>>
72-
>>> # Replace "insights" with the method corresponding to the web service
73-
>>> # that you are using, e.g., "country", "city".
74-
>>> response = client.insights('128.101.101.101')
117+
>>> # Replace "insights" with the method corresponding to the web service
118+
>>> # that you are using, e.g., "country", "city".
119+
>>> response = await client.insights('203.0.113.0')
75120
>>>
76-
>>> response.country.iso_code
121+
>>> response.country.iso_code
77122
'US'
78-
>>> response.country.name
123+
>>> response.country.name
79124
'United States'
80-
>>> response.country.names['zh-CN']
125+
>>> response.country.names['zh-CN']
81126
u'美国'
82127
>>>
83-
>>> response.subdivisions.most_specific.name
128+
>>> response.subdivisions.most_specific.name
84129
'Minnesota'
85-
>>> response.subdivisions.most_specific.iso_code
130+
>>> response.subdivisions.most_specific.iso_code
86131
'MN'
87132
>>>
88-
>>> response.city.name
133+
>>> response.city.name
89134
'Minneapolis'
90135
>>>
91-
>>> response.postal.code
136+
>>> response.postal.code
92137
'55455'
93138
>>>
94-
>>> response.location.latitude
139+
>>> response.location.latitude
95140
44.9733
96-
>>> response.location.longitude
141+
>>> response.location.longitude
97142
-93.2323
98143
>>>
99-
>>> response.traits.network
100-
IPv4Network('128.101.101.101/32')
144+
>>> response.traits.network
145+
IPv4Network('203.0.113.0/32')
101146
102147
Web Service Client Exceptions
103148
-----------------------------
@@ -131,39 +176,37 @@ City Database
131176
>>>
132177
>>> # This creates a Reader object. You should use the same object
133178
>>> # across multiple requests as creation of it is expensive.
134-
>>> reader = geoip2.database.Reader('/path/to/GeoLite2-City.mmdb')
179+
>>> with geoip2.database.Reader('/path/to/GeoLite2-City.mmdb') as reader:
135180
>>>
136-
>>> # Replace "city" with the method corresponding to the database
137-
>>> # that you are using, e.g., "country".
138-
>>> response = reader.city('128.101.101.101')
181+
>>> # Replace "city" with the method corresponding to the database
182+
>>> # that you are using, e.g., "country".
183+
>>> response = reader.city('203.0.113.0')
139184
>>>
140-
>>> response.country.iso_code
185+
>>> response.country.iso_code
141186
'US'
142-
>>> response.country.name
187+
>>> response.country.name
143188
'United States'
144-
>>> response.country.names['zh-CN']
189+
>>> response.country.names['zh-CN']
145190
u'美国'
146191
>>>
147-
>>> response.subdivisions.most_specific.name
192+
>>> response.subdivisions.most_specific.name
148193
'Minnesota'
149-
>>> response.subdivisions.most_specific.iso_code
194+
>>> response.subdivisions.most_specific.iso_code
150195
'MN'
151196
>>>
152-
>>> response.city.name
197+
>>> response.city.name
153198
'Minneapolis'
154199
>>>
155-
>>> response.postal.code
200+
>>> response.postal.code
156201
'55455'
157202
>>>
158-
>>> response.location.latitude
203+
>>> response.location.latitude
159204
44.9733
160-
>>> response.location.longitude
205+
>>> response.location.longitude
161206
-93.2323
162207
>>>
163-
>>> response.traits.network
164-
IPv4Network('128.101.101.0/24')
165-
>>>
166-
>>> reader.close()
208+
>>> response.traits.network
209+
IPv4Network('203.0.113.0/24')
167210
168211
Anonymous IP Database
169212
^^^^^^^^^^^^^^^^^^^^^
@@ -174,25 +217,24 @@ Anonymous IP Database
174217
>>>
175218
>>> # This creates a Reader object. You should use the same object
176219
>>> # across multiple requests as creation of it is expensive.
177-
>>> reader = geoip2.database.Reader('/path/to/GeoIP2-Anonymous-IP.mmdb')
220+
>>> with geoip2.database.Reader('/path/to/GeoIP2-Anonymous-IP.mmdb') as reader:
178221
>>>
179-
>>> response = reader.anonymous_ip('85.25.43.84')
222+
>>> response = reader.anonymous_ip('203.0.113.0')
180223
>>>
181-
>>> response.is_anonymous
224+
>>> response.is_anonymous
182225
True
183-
>>> response.is_anonymous_vpn
226+
>>> response.is_anonymous_vpn
184227
False
185-
>>> response.is_hosting_provider
228+
>>> response.is_hosting_provider
186229
False
187-
>>> response.is_public_proxy
230+
>>> response.is_public_proxy
188231
False
189-
>>> response.is_tor_exit_node
232+
>>> response.is_tor_exit_node
190233
True
191-
>>> response.ip_address
192-
'85.25.43.84'
193-
>>> response.network
194-
IPv4Network('85.25.43.0/24')
195-
>>> reader.close()
234+
>>> response.ip_address
235+
'203.0.113.0'
236+
>>> response.network
237+
IPv4Network('203.0.113.0/24')
196238
197239
ASN Database
198240
^^^^^^^^^^^^
@@ -204,11 +246,15 @@ ASN Database
204246
>>> # This creates a Reader object. You should use the same object
205247
>>> # across multiple requests as creation of it is expensive.
206248
>>> with geoip2.database.Reader('/path/to/GeoLite2-ASN.mmdb') as reader:
207-
>>> response = reader.asn('1.128.0.0')
249+
>>> response = reader.asn('203.0.113.0')
208250
>>> response.autonomous_system_number
209251
1221
210252
>>> response.autonomous_system_organization
211253
'Telstra Pty Ltd'
254+
>>> response.ip_address
255+
'203.0.113.0'
256+
>>> response.network
257+
IPv4Network('203.0.113.0/24')
212258
213259
Connection-Type Database
214260
^^^^^^^^^^^^^^^^^^^^^^^^
@@ -219,17 +265,14 @@ Connection-Type Database
219265
>>>
220266
>>> # This creates a Reader object. You should use the same object
221267
>>> # across multiple requests as creation of it is expensive.
222-
>>> reader = geoip2.database.Reader('/path/to/GeoIP2-Connection-Type.mmdb')
223-
>>>
224-
>>> response = reader.connection_type('128.101.101.101')
225-
>>>
226-
>>> response.connection_type
268+
>>> with geoip2.database.Reader('/path/to/GeoIP2-Connection-Type.mmdb') as reader:
269+
>>> response = reader.connection_type('203.0.113.0')
270+
>>> response.connection_type
227271
'Corporate'
228-
>>> response.ip_address
229-
'128.101.101.101'
230-
>>> response.network
231-
IPv4Network('128.101.101.101/24')
232-
>>> reader.close()
272+
>>> response.ip_address
273+
'203.0.113.0'
274+
>>> response.network
275+
IPv4Network('203.0.113.0/24')
233276
234277
235278
Domain Database
@@ -241,15 +284,12 @@ Domain Database
241284
>>>
242285
>>> # This creates a Reader object. You should use the same object
243286
>>> # across multiple requests as creation of it is expensive.
244-
>>> reader = geoip2.database.Reader('/path/to/GeoIP2-Domain.mmdb')
245-
>>>
246-
>>> response = reader.domain('128.101.101.101')
247-
>>>
248-
>>> response.domain
287+
>>> with geoip2.database.Reader('/path/to/GeoIP2-Domain.mmdb') as reader:
288+
>>> response = reader.domain('203.0.113.0')
289+
>>> response.domain
249290
'umn.edu'
250-
>>> response.ip_address
251-
'128.101.101.101'
252-
>>> reader.close()
291+
>>> response.ip_address
292+
'203.0.113.0'
253293
254294
Enterprise Database
255295
^^^^^^^^^^^^^^^^^^^
@@ -263,7 +303,7 @@ Enterprise Database
263303
>>> with geoip2.database.Reader('/path/to/GeoIP2-Enterprise.mmdb') as reader:
264304
>>>
265305
>>> # Use the .enterprise method to do a lookup in the Enterprise database
266-
>>> response = reader.enterprise('128.101.101.101')
306+
>>> response = reader.enterprise('203.0.113.0')
267307
>>>
268308
>>> response.country.confidence
269309
99
@@ -297,7 +337,7 @@ Enterprise Database
297337
-93.2323
298338
>>>
299339
>>> response.traits.network
300-
IPv4Network('128.101.101.0/24')
340+
IPv4Network('203.0.113.0/24')
301341
302342
303343
ISP Database
@@ -309,23 +349,20 @@ ISP Database
309349
>>>
310350
>>> # This creates a Reader object. You should use the same object
311351
>>> # across multiple requests as creation of it is expensive.
312-
>>> reader = geoip2.database.Reader('/path/to/GeoIP2-ISP.mmdb')
313-
>>>
314-
>>> response = reader.isp('1.128.0.0')
315-
>>>
316-
>>> response.autonomous_system_number
352+
>>> with geoip2.database.Reader('/path/to/GeoIP2-ISP.mmdb') as reader:
353+
>>> response = reader.isp('203.0.113.0')
354+
>>> response.autonomous_system_number
317355
1221
318-
>>> response.autonomous_system_organization
356+
>>> response.autonomous_system_organization
319357
'Telstra Pty Ltd'
320-
>>> response.isp
358+
>>> response.isp
321359
'Telstra Internet'
322-
>>> response.organization
360+
>>> response.organization
323361
'Telstra Internet'
324-
>>> response.ip_address
325-
'1.128.0.0'
326-
>>> response.network
327-
IPv4Network('1.128.0.0/16')
328-
>>> reader.close()
362+
>>> response.ip_address
363+
'203.0.113.0'
364+
>>> response.network
365+
IPv4Network('203.0.113.0/24')
329366
330367
Database Reader Exceptions
331368
--------------------------

0 commit comments

Comments
 (0)