ipwhois-python 1.0.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,16 @@
1
+ __pycache__/
2
+ *.py[cod]
3
+ *.egg-info/
4
+ .pytest_cache/
5
+ .mypy_cache/
6
+ .ruff_cache/
7
+ build/
8
+ dist/
9
+ *.whl
10
+ *.tar.gz
11
+ .venv/
12
+ venv/
13
+ env/
14
+ .DS_Store
15
+ .idea/
16
+ .vscode/
@@ -0,0 +1,12 @@
1
+ # Changelog
2
+
3
+ All notable changes to `ipwhois-python` will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [1.0.0] - 2026-05-08
9
+
10
+ ### Added
11
+
12
+ - Initial release.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 ipwhois.io
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,370 @@
1
+ Metadata-Version: 2.4
2
+ Name: ipwhois-python
3
+ Version: 1.0.0
4
+ Summary: Official Python client for the ipwhois.io IP Geolocation API. Simple, dependency-free, supports single and bulk IP lookups.
5
+ Project-URL: Homepage, https://ipwhois.io
6
+ Project-URL: Documentation, https://ipwhois.io/documentation
7
+ Project-URL: Source, https://github.com/IPWhois/ipwhois-python
8
+ Project-URL: Issues, https://github.com/IPWhois/ipwhois-python/issues
9
+ Author: ipwhois.io
10
+ License: MIT License
11
+
12
+ Copyright (c) 2026 ipwhois.io
13
+
14
+ Permission is hereby granted, free of charge, to any person obtaining a copy
15
+ of this software and associated documentation files (the "Software"), to deal
16
+ in the Software without restriction, including without limitation the rights
17
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
18
+ copies of the Software, and to permit persons to whom the Software is
19
+ furnished to do so, subject to the following conditions:
20
+
21
+ The above copyright notice and this permission notice shall be included in all
22
+ copies or substantial portions of the Software.
23
+
24
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
25
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
26
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
27
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
28
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
29
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30
+ SOFTWARE.
31
+ License-File: LICENSE
32
+ Keywords: geoip,geolocation,ip-api,ip-geolocation,ip-locator,ip-lookup,ipwhois
33
+ Classifier: Development Status :: 5 - Production/Stable
34
+ Classifier: Intended Audience :: Developers
35
+ Classifier: License :: OSI Approved :: MIT License
36
+ Classifier: Operating System :: OS Independent
37
+ Classifier: Programming Language :: Python
38
+ Classifier: Programming Language :: Python :: 3
39
+ Classifier: Programming Language :: Python :: 3 :: Only
40
+ Classifier: Programming Language :: Python :: 3.8
41
+ Classifier: Programming Language :: Python :: 3.9
42
+ Classifier: Programming Language :: Python :: 3.10
43
+ Classifier: Programming Language :: Python :: 3.11
44
+ Classifier: Programming Language :: Python :: 3.12
45
+ Classifier: Programming Language :: Python :: 3.13
46
+ Classifier: Topic :: Internet
47
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
48
+ Classifier: Typing :: Typed
49
+ Requires-Python: >=3.8
50
+ Provides-Extra: dev
51
+ Requires-Dist: pytest>=7.0; extra == 'dev'
52
+ Description-Content-Type: text/markdown
53
+
54
+ # ipwhois-python
55
+
56
+ [![PyPI Version](https://img.shields.io/pypi/v/ipwhois-python.svg)](https://pypi.org/project/ipwhois-python/)
57
+ [![Python Versions](https://img.shields.io/pypi/pyversions/ipwhois-python.svg)](https://pypi.org/project/ipwhois-python/)
58
+ [![License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
59
+
60
+ Official, dependency-free Python client for the [ipwhois.io](https://ipwhois.io) IP Geolocation API.
61
+
62
+ - ✅ Single and bulk IP lookups (IPv4 and IPv6)
63
+ - ✅ Works with both the **Free** and **Paid** plans
64
+ - ✅ HTTPS by default
65
+ - ✅ Localisation, field selection, threat detection, rate info
66
+ - ✅ Never raises — all errors returned as `success: False` dicts
67
+ - ✅ No external dependencies — only the Python standard library
68
+ - ✅ Python 3.8+
69
+
70
+ ## Installation
71
+
72
+ ```bash
73
+ pip install ipwhois-python
74
+ ```
75
+
76
+ ## Free vs Paid plan
77
+
78
+ The same `Client` class is used for both plans. The only difference is whether
79
+ you pass an API key:
80
+
81
+ - **Free plan** — create the client **without arguments**. No API key, no
82
+ signup required. Suitable for low-traffic and non-commercial use.
83
+ - **Paid plan** — create the client **with your API key** from
84
+ <https://ipwhois.io>. Higher limits, plus access to bulk lookups and
85
+ threat-detection data.
86
+
87
+ ```python
88
+ from ipwhois import Client
89
+
90
+ free = Client() # Free plan — no API key
91
+ paid = Client("YOUR_API_KEY") # Paid plan — with API key
92
+ ```
93
+
94
+ Everything else (`lookup()`, options, error handling) is identical.
95
+
96
+ ## Quick start — Free plan (no API key)
97
+
98
+ ```python
99
+ from ipwhois import Client
100
+
101
+ client = Client() # no API key
102
+
103
+ info = client.lookup("8.8.8.8")
104
+
105
+ print(info["country"], info["flag"]["emoji"])
106
+ # → United States 🇺🇸
107
+
108
+ print(f"{info['city']}, {info['region']}")
109
+ # → Mountain View, California
110
+ ```
111
+
112
+ ## Quick start — Paid plan (with API key)
113
+
114
+ Get an API key at <https://ipwhois.io> and pass it to the constructor:
115
+
116
+ ```python
117
+ from ipwhois import Client
118
+
119
+ client = Client("YOUR_API_KEY") # with API key
120
+
121
+ info = client.lookup("8.8.8.8")
122
+
123
+ print(info["country"], info["flag"]["emoji"])
124
+ # → United States 🇺🇸
125
+
126
+ print(f"{info['city']}, {info['region']}")
127
+ # → Mountain View, California
128
+ ```
129
+
130
+ > ℹ️ Pass nothing to look up your own public IP: `client.lookup()` — works
131
+ > on both plans.
132
+
133
+ ## Lookup options
134
+
135
+ Every option below can be passed per call as a keyword argument, or set once
136
+ on the client as a default.
137
+
138
+ | Option | Type | Plans needed | Description |
139
+ | ------------ | ------- | -------------------- | ---------------------------------------------------------------------- |
140
+ | `lang` | str | Free + Paid | One of: `en`, `ru`, `de`, `es`, `pt-BR`, `fr`, `zh-CN`, `ja` |
141
+ | `fields` | list | Free + Paid | Restrict the response to specific fields (e.g. `["country", "city"]`) |
142
+ | `output` | str | Free + Paid | `json` (default), `xml`, `csv` |
143
+ | `rate` | bool | Basic and above | Include the `rate` block (`limit`, `remaining`) |
144
+ | `security` | bool | Business and above | Include the `security` block (proxy/vpn/tor/hosting) |
145
+
146
+ ### Setting defaults once
147
+
148
+ If you make many calls with the same options, set them once and forget:
149
+
150
+ ```python
151
+ # Free plan
152
+ client = (
153
+ Client()
154
+ .set_language("en")
155
+ .set_fields(["country", "city", "flag.emoji"])
156
+ .set_timeout(8)
157
+ )
158
+
159
+ client.lookup("8.8.8.8") # uses all of the above
160
+ client.lookup("1.1.1.1", lang="de") # per-call options override defaults
161
+ ```
162
+
163
+ ```python
164
+ # Paid plan
165
+ client = (
166
+ Client("YOUR_API_KEY")
167
+ .set_language("en")
168
+ .set_fields(["country", "city", "flag.emoji"])
169
+ .set_timeout(8)
170
+ )
171
+
172
+ client.lookup("8.8.8.8") # uses all of the above
173
+ client.lookup("1.1.1.1", lang="de") # per-call options override defaults
174
+ ```
175
+
176
+ > ℹ️ Paid plans additionally support `set_security(True)` (Business+) and
177
+ > `set_rate(True)` (Basic+). See the table above for what's available where.
178
+
179
+ ## HTTPS encryption
180
+
181
+ By default, all requests are sent over HTTPS. If you need to disable it (for
182
+ example, in environments without an up-to-date CA bundle), pass `ssl=False`
183
+ to the constructor:
184
+
185
+ ```python
186
+ from ipwhois import Client
187
+
188
+ # Free plan
189
+ client = Client(ssl=False)
190
+ ```
191
+
192
+ ```python
193
+ from ipwhois import Client
194
+
195
+ # Paid plan
196
+ client = Client("YOUR_API_KEY", ssl=False)
197
+ ```
198
+
199
+ > ℹ️ HTTPS is strongly recommended for production traffic — your API key is
200
+ > sent in the query string and would otherwise travel in clear text.
201
+
202
+ ## Bulk lookup (Paid plan only)
203
+
204
+ The bulk endpoint sends **up to 100 IPs** in a single GET request. Each
205
+ address counts as one credit. Available on the **Business** and **Unlimited**
206
+ plans.
207
+
208
+ ```python
209
+ from ipwhois import Client
210
+
211
+ client = Client("YOUR_API_KEY")
212
+
213
+ results = client.bulk_lookup([
214
+ "8.8.8.8",
215
+ "1.1.1.1",
216
+ "208.67.222.222",
217
+ "2c0f:fb50:4003::", # IPv6 is fine — mix freely
218
+ ])
219
+
220
+ for row in results:
221
+ if row.get("success") is False:
222
+ # Per-IP errors (e.g. "Invalid IP address") are returned inline,
223
+ # they do NOT raise — the rest of the batch is still usable.
224
+ print(f"skip {row['ip']}: {row['message']}")
225
+ continue
226
+ print(f"{row['ip']} → {row['country']}")
227
+ ```
228
+
229
+ > ℹ️ Bulk requires an API key. Calling `bulk_lookup()` without one will fail
230
+ > at the API level.
231
+
232
+ ## Error handling
233
+
234
+ **The library never raises.** Every failure — invalid IP, bad API key, rate
235
+ limit, network outage, bad options — comes back inside the response dict
236
+ with `success` set to `False` and a `message`. Just check
237
+ `info["success"]` after every call:
238
+
239
+ ```python
240
+ info = client.lookup("8.8.8.8")
241
+
242
+ if not info["success"]:
243
+ print(f"Lookup failed: {info['message']}")
244
+ return
245
+
246
+ print(info["country"])
247
+ ```
248
+
249
+ This means an outage of the ipwhois.io API (or of your machine's DNS,
250
+ connection, etc.) will never surface as an unhandled exception in your
251
+ application — you decide how to react.
252
+
253
+ ### Error response fields
254
+
255
+ Every error response contains `success: False` and a `message`. Some errors
256
+ include extra fields you can branch on:
257
+
258
+ | Field | When it's present |
259
+ | -------------- | ---------------------------------------------------------------------------- |
260
+ | `error_type` | `'network'` or `'invalid_argument'` — for non-API errors |
261
+ | `http_status` | On HTTP 4xx / 5xx responses |
262
+ | `retry_after` | On HTTP 429 if the API sent a `Retry-After` header |
263
+
264
+ ```python
265
+ import time
266
+
267
+ info = client.lookup("8.8.8.8")
268
+
269
+ if not info["success"]:
270
+ if info.get("http_status") == 429:
271
+ time.sleep(info.get("retry_after", 60))
272
+ # ...retry
273
+
274
+ if info.get("error_type") == "network":
275
+ # DNS failure, connection refused, timeout, ...
276
+ pass
277
+
278
+ print(f"Error: {info['message']}")
279
+ ```
280
+
281
+ ## Response shape
282
+
283
+ A successful response includes (depending on your plan and selected options):
284
+
285
+ ```jsonc
286
+ {
287
+ "ip": "8.8.4.4",
288
+ "success": true,
289
+ "type": "IPv4",
290
+ "continent": "North America",
291
+ "continent_code": "NA",
292
+ "country": "United States",
293
+ "country_code": "US",
294
+ "region": "California",
295
+ "region_code": "CA",
296
+ "city": "Mountain View",
297
+ "latitude": 37.3860517,
298
+ "longitude": -122.0838511,
299
+ "is_eu": false,
300
+ "postal": "94039",
301
+ "calling_code": "1",
302
+ "capital": "Washington D.C.",
303
+ "borders": "CA,MX",
304
+ "flag": {
305
+ "img": "https://cdn.ipwhois.io/flags/us.svg",
306
+ "emoji": "🇺🇸",
307
+ "emoji_unicode": "U+1F1FA U+1F1F8"
308
+ },
309
+ "connection": {
310
+ "asn": 15169,
311
+ "org": "Google LLC",
312
+ "isp": "Google LLC",
313
+ "domain": "google.com"
314
+ },
315
+ "timezone": {
316
+ "id": "America/Los_Angeles",
317
+ "abbr": "PDT",
318
+ "is_dst": true,
319
+ "offset": -25200,
320
+ "utc": "-07:00",
321
+ "current_time": "2026-05-08T14:31:48-07:00"
322
+ },
323
+ "currency": {
324
+ "name": "US Dollar",
325
+ "code": "USD",
326
+ "symbol": "$",
327
+ "plural": "US dollars",
328
+ "exchange_rate": 1
329
+ },
330
+ "security": {
331
+ "anonymous": false,
332
+ "proxy": false,
333
+ "vpn": false,
334
+ "tor": false,
335
+ "hosting": false
336
+ },
337
+ "rate": {
338
+ "limit": 250000,
339
+ "remaining": 50155
340
+ }
341
+ }
342
+ ```
343
+
344
+ For the full field reference, see the [official documentation](https://ipwhois.io/documentation).
345
+
346
+ An **error** response looks like:
347
+
348
+ ```jsonc
349
+ {
350
+ "success": false,
351
+ "message": "Invalid IP address",
352
+ "http_status": 400 // present for HTTP 4xx / 5xx
353
+ // "retry_after": 60 // additionally present on HTTP 429 if the API sent a Retry-After header
354
+ // "error_type": "network" // present for non-API errors: 'network', 'invalid_argument'
355
+ }
356
+ ```
357
+
358
+ ## Requirements
359
+
360
+ - Python **3.8** or newer
361
+ - No third-party dependencies — only the standard library (`urllib`, `json`)
362
+
363
+ ## Contributing
364
+
365
+ Issues and pull requests are welcome on
366
+ [GitHub](https://github.com/IPWhois/ipwhois-python).
367
+
368
+ ## License
369
+
370
+ [MIT](LICENSE) © ipwhois.io