0
# Data Structures and Utilities
1
2
Response objects, caching system, exception handling, and utility functions for data formatting, validation, and configuration management in the IPInfo Python library.
3
4
## Capabilities
5
6
### Details Response Object
7
8
The primary response object that encapsulates IP address information with attribute-based access and data enrichment functionality.
9
10
```python { .api }
11
class Details:
12
def __init__(self, details):
13
"""
14
Initialize Details object with IP information dictionary.
15
16
Parameters:
17
- details (dict): Dictionary containing IP address information
18
"""
19
20
def __getattr__(self, attr):
21
"""
22
Return attribute if it exists in details, else raise AttributeError.
23
24
Parameters:
25
- attr (str): Attribute name to access
26
27
Returns:
28
Any: Value of the requested attribute
29
30
Raises:
31
AttributeError: When attribute doesn't exist in details
32
"""
33
34
@property
35
def all(self):
36
"""
37
Return all details as dictionary.
38
39
Returns:
40
dict: Complete details dictionary
41
"""
42
```
43
44
### Exception Classes
45
46
Specialized exception classes for handling API errors, quota limits, and timeout conditions.
47
48
```python { .api }
49
class RequestQuotaExceededError(Exception):
50
"""
51
Error indicating that user's monthly request quota has been exceeded.
52
53
Raised when API returns 429 status code.
54
"""
55
56
class TimeoutExceededError(Exception):
57
"""
58
Error indicating that some timeout has been exceeded.
59
60
Raised when operation exceeds specified timeout limits.
61
"""
62
63
class APIError(Exception):
64
def __init__(self, error_code, error_json):
65
"""
66
General API error with status code and response details.
67
68
Parameters:
69
- error_code (int): HTTP status code
70
- error_json (dict): Error response JSON
71
"""
72
73
def __str__(self):
74
"""
75
Return formatted error string with code and JSON response.
76
77
Returns:
78
str: Formatted error message
79
"""
80
```
81
82
### Cache System
83
84
Abstract cache interface and default LRU implementation for efficient IP data caching.
85
86
```python { .api }
87
class CacheInterface:
88
"""Abstract interface for custom cache implementations."""
89
90
def __contains__(self, key):
91
"""Check if key exists in cache."""
92
93
def __setitem__(self, key, value):
94
"""Set cache value for key."""
95
96
def __getitem__(self, key):
97
"""Get cache value for key."""
98
99
def __delitem__(self, key):
100
"""Delete cache entry for key."""
101
102
class DefaultCache(CacheInterface):
103
def __init__(self, **cache_options):
104
"""
105
Default in-memory LRU cache with TTL support.
106
107
Parameters:
108
- **cache_options: Options passed to cachetools.TTLCache
109
- maxsize (int): Maximum cache entries (default: 4096)
110
- ttl (int): Time to live in seconds (default: 86400)
111
"""
112
113
def __contains__(self, key):
114
"""Check if key exists in cache."""
115
116
def __setitem__(self, key, value):
117
"""Set cache value for key."""
118
119
def __getitem__(self, key):
120
"""Get cache value for key."""
121
122
def __delitem__(self, key):
123
"""Delete cache entry for key."""
124
```
125
126
### Utility Functions
127
128
Helper functions for HTTP headers, data formatting, file I/O, and cache key management.
129
130
```python { .api }
131
def get_headers(access_token, custom_headers):
132
"""
133
Build headers for request to IPinfo API.
134
135
Parameters:
136
- access_token (str, optional): API access token
137
- custom_headers (dict, optional): Custom HTTP headers
138
139
Returns:
140
dict: Complete headers dictionary with user-agent, accept, and authorization
141
"""
142
143
def format_details(details, countries, eu_countries, countries_flags, countries_currencies, continents):
144
"""
145
Format details dictionary with additional country and geographic data.
146
147
Adds country_name, isEU, country_flag_url, country_flag,
148
country_currency, continent, latitude, and longitude fields.
149
150
Parameters:
151
- details (dict): Raw IP details to format
152
- countries (dict): Country code to name mappings
153
- eu_countries (list): List of EU country codes
154
- countries_flags (dict): Country flag data
155
- countries_currencies (dict): Country currency data
156
- continents (dict): Continent mappings
157
"""
158
159
def read_coords(location):
160
"""
161
Parse location string into latitude and longitude tuple.
162
163
Parameters:
164
- location (str): Location string in format "lat,lon"
165
166
Returns:
167
tuple: (latitude, longitude) as strings, or (None, None) if invalid
168
"""
169
170
def read_json_file(json_file):
171
"""
172
Read and parse JSON file from package data directory.
173
174
Parameters:
175
- json_file (str): Filename relative to package directory
176
177
Returns:
178
dict: Parsed JSON data
179
"""
180
181
def return_or_fail(raise_on_fail, e, v):
182
"""
183
Either raise exception or return value based on flag.
184
185
Parameters:
186
- raise_on_fail (bool): Whether to raise exception
187
- e (Exception): Exception to raise
188
- v (Any): Value to return if not raising
189
190
Returns:
191
Any: Returns v if raise_on_fail is False
192
193
Raises:
194
Exception: Raises e if raise_on_fail is True
195
"""
196
197
def cache_key(k):
198
"""
199
Transform user input key into versioned cache key.
200
201
Parameters:
202
- k (str): User input key
203
204
Returns:
205
str: Versioned cache key
206
"""
207
```
208
209
### Bogon Detection
210
211
Functions for identifying private and reserved IP address ranges.
212
213
```python { .api }
214
def is_bogon(ip_address):
215
"""
216
Check if IP address is a bogon (private/reserved address).
217
218
Parameters:
219
- ip_address (str): IP address to check
220
221
Returns:
222
bool: True if IP is in bogon networks, False otherwise
223
"""
224
225
# Predefined bogon networks
226
BOGON_NETWORKS = [
227
# IPv4 bogon networks
228
ipaddress.ip_network("0.0.0.0/8"), # This network
229
ipaddress.ip_network("10.0.0.0/8"), # Private-use
230
ipaddress.ip_network("127.0.0.0/8"), # Loopback
231
ipaddress.ip_network("169.254.0.0/16"), # Link-local
232
ipaddress.ip_network("172.16.0.0/12"), # Private-use
233
ipaddress.ip_network("192.168.0.0/16"), # Private-use
234
# ... additional bogon networks
235
]
236
```
237
238
### Data Constants
239
240
Pre-loaded geographic and internationalization data for response enrichment.
241
242
```python { .api }
243
# Geographic data mappings
244
continents = {
245
"US": {"code": "NA", "name": "North America"},
246
"GB": {"code": "EU", "name": "Europe"},
247
# ... complete country to continent mappings
248
}
249
250
countries = {
251
"US": "United States",
252
"GB": "United Kingdom",
253
# ... complete country code to name mappings
254
}
255
256
countries_currencies = {
257
"US": {"code": "USD", "symbol": "$"},
258
"GB": {"code": "GBP", "symbol": "£"},
259
# ... complete currency mappings
260
}
261
262
eu_countries = [
263
"AT", "BE", "BG", "HR", "CY", "CZ", "DK", "EE", "FI", "FR",
264
"DE", "GR", "HU", "IE", "IT", "LV", "LT", "LU", "MT", "NL",
265
"PL", "PT", "RO", "SK", "SI", "ES", "SE"
266
]
267
268
countries_flags = {
269
"US": {"emoji": "🇺🇸", "unicode": "U+1F1FA U+1F1F8"},
270
"GB": {"emoji": "🇬🇧", "unicode": "U+1F1EC U+1F1E7"},
271
# ... complete flag mappings
272
}
273
274
# API endpoints and configuration
275
API_URL = "https://ipinfo.io"
276
LITE_API_URL = "https://api.ipinfo.io/lite"
277
COUNTRY_FLAGS_URL = "https://cdn.ipinfo.io/static/images/countries-flags/"
278
BATCH_MAX_SIZE = 1000
279
CACHE_MAXSIZE = 4096
280
CACHE_TTL = 86400 # 24 hours
281
REQUEST_TIMEOUT_DEFAULT = 2
282
BATCH_REQ_TIMEOUT_DEFAULT = 5
283
```
284
285
## Usage Examples
286
287
### Custom Cache Implementation
288
289
```python
290
import ipinfo
291
from ipinfo.cache.interface import CacheInterface
292
import redis
293
294
class RedisCache(CacheInterface):
295
"""Redis-based cache implementation"""
296
297
def __init__(self, redis_client, ttl=86400):
298
self.redis = redis_client
299
self.ttl = ttl
300
301
def __contains__(self, key):
302
return self.redis.exists(key)
303
304
def __setitem__(self, key, value):
305
import json
306
self.redis.setex(key, self.ttl, json.dumps(value))
307
308
def __getitem__(self, key):
309
import json
310
value = self.redis.get(key)
311
if value is None:
312
raise KeyError(key)
313
return json.loads(value)
314
315
def __delitem__(self, key):
316
self.redis.delete(key)
317
318
# Use custom cache
319
redis_client = redis.Redis()
320
custom_cache = RedisCache(redis_client)
321
handler = ipinfo.getHandler('token', cache=custom_cache)
322
```
323
324
### Working with Details Object
325
326
```python
327
import ipinfo
328
329
handler = ipinfo.getHandler('your_token')
330
details = handler.getDetails('8.8.8.8')
331
332
# Access individual attributes
333
print(details.city) # Mountain View
334
print(details.country) # US
335
print(details.country_name) # United States
336
print(details.isEU) # False
337
print(details.latitude) # 37.3860
338
print(details.longitude) # -122.0838
339
340
# Access all data as dictionary
341
all_data = details.all
342
print(all_data['hostname']) # dns.google
343
344
# Handle missing attributes
345
try:
346
print(details.nonexistent_field)
347
except AttributeError as e:
348
print(f"Field not available: {e}")
349
```
350
351
### Error Handling
352
353
```python
354
import ipinfo
355
from ipinfo.exceptions import RequestQuotaExceededError, TimeoutExceededError
356
from ipinfo.error import APIError
357
358
handler = ipinfo.getHandler('invalid_token')
359
360
try:
361
details = handler.getDetails('8.8.8.8')
362
except RequestQuotaExceededError:
363
print("Quota exceeded - upgrade your plan")
364
except APIError as e:
365
print(f"API Error {e.error_code}")
366
print(f"Details: {e.error_json}")
367
except TimeoutExceededError:
368
print("Request timed out")
369
```
370
371
### Bogon Detection
372
373
```python
374
from ipinfo.bogon import is_bogon
375
376
# Check if IP is private/reserved
377
print(is_bogon('192.168.1.1')) # True (private)
378
print(is_bogon('8.8.8.8')) # False (public)
379
print(is_bogon('127.0.0.1')) # True (loopback)
380
```
381
382
### Custom Data Files
383
384
```python
385
import ipinfo
386
387
# Custom country names (e.g., for localization)
388
custom_countries = {
389
"US": "États-Unis",
390
"FR": "France",
391
"DE": "Allemagne"
392
}
393
394
# Custom EU country list
395
custom_eu = ["FR", "DE", "IT", "ES"] # Subset for example
396
397
handler = ipinfo.getHandler(
398
'your_token',
399
countries=custom_countries,
400
eu_countries=custom_eu
401
)
402
403
details = handler.getDetails('8.8.8.8')
404
print(details.country_name) # Uses custom mapping
405
print(details.isEU) # Uses custom EU list
406
```
407
408
## Types
409
410
```python { .api }
411
# Details object structure
412
DetailsDict = {
413
# Core API fields
414
'ip': str,
415
'hostname': str,
416
'city': str,
417
'region': str,
418
'country': str,
419
'loc': str, # "latitude,longitude"
420
'org': str,
421
'postal': str,
422
'timezone': str,
423
424
# Enhanced fields (added by library)
425
'country_name': str,
426
'latitude': str,
427
'longitude': str,
428
'isEU': bool,
429
'country_flag': dict, # {"emoji": str, "unicode": str}
430
'country_currency': dict, # {"code": str, "symbol": str}
431
'continent': dict, # {"code": str, "name": str}
432
'country_flag_url': str,
433
434
# Optional fields (may be present)
435
'asn': dict, # ASN information
436
'company': dict, # Company information
437
'carrier': dict, # Mobile carrier info
438
'privacy': dict, # Privacy/VPN detection
439
'abuse': dict, # Abuse contact info
440
'domains': dict # Associated domains
441
}
442
443
# Cache interface type
444
CacheInterface = {
445
'__contains__': callable,
446
'__getitem__': callable,
447
'__setitem__': callable,
448
'__delitem__': callable
449
}
450
451
# Geographic data types
452
CountryMapping = dict # Country code -> name
453
ContinentMapping = dict # Country code -> {"code": str, "name": str}
454
FlagMapping = dict # Country code -> {"emoji": str, "unicode": str}
455
CurrencyMapping = dict # Country code -> {"code": str, "symbol": str}
456
```