8000 AddressNotFoundError: add .network · maxmind/GeoIP2-python@79d0308 · GitHub
[go: up one dir, main page]

Skip to content

Commit 79d0308

Browse files
committed
AddressNotFoundError: add .network
1 parent 115d1ed commit 79d0308

File tree

3 files changed

+63
-2
lines changed

3 files changed

+63
-2
lines changed

README.rst

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -400,6 +400,31 @@ or there is a bug in the reader, a ``maxminddb.InvalidDatabaseError`` will be
400400
raised with a description of the problem. If an IP address is not in the
401401
database, a ``AddressNotFoundError`` will be raised.
402402

403+
``AddressNotFoundError`` references the largest subnet where no address would be
404+
found. This can be used to efficiently enumerate entire subnets:
405+
406+
.. code-block:: python
407+
408+
import geoip2.database
409+
import geoip2.errors
410+
import ipaddress
411+
412+
# This creates a Reader object. You should use the same object
413+
# across multiple requests as creation of it is expensive.
414+
with geoip2.database.Reader('/path/to/GeoLite2-ASN.mmdb') as reader:
415+
network = ipaddress.ip_network("192.128.0.0/15")
416+
417+
ip_address = network[0]
418+
while ip_address in network:
419+
try:
420+
response = reader.asn(ip_address)
421+
response_network = response.network
422+
except geoip2.errors.AddressNotFoundError as e:
423+
response = None
424+
response_network = e.network
425+
print(f"{response_network}: {response!r}")
426+
ip_address = response_network[-1] + 1 # move to next subnet
427+
403428
Values to use for Database or Dictionary Keys
404429
---------------------------------------------
405430

geoip2/database.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,8 @@ def _get(self, database_type: str, ip_address: IPAddress) -> Any:
239239
if record is None:
240240
raise geoip2.errors.AddressNotFoundError(
241241
f"The address {ip_address} is not in the database.",
242+
str(ip_address),
243+
prefix_len,
242244
)
243245
return record, prefix_len
244246

geoip2/errors.py

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@
44
55
"""
66

7-
from typing import Optional
7+
import ipaddress
8+
9+
from typing import Optional, Union
810

911

1012
class GeoIP2Error(RuntimeError):
@@ -17,7 +19,39 @@ class GeoIP2Error(RuntimeError):
1719

1820

1921
class AddressNotFoundError(GeoIP2Error):
20-
"""The address you were looking up was not found."""
22+
"""The address you were looking up was not found.
23+
24+
.. attribute:: ip_address
25+
26+
The IP address used in the lookup.
27+
28+
:type: str
29+
30+
.. attribute:: network
31+
32+
The network associated with the error. In particular, this is the
33+
largest network where no address would be found.
34+
35+
"""
36+
37+
def __init__(
38+
self,
39+
message: str,
40+
ip_address: Optional[str] = None,
41+
prefix_len: Optional[int] = None,
42+
) -> None:
43+
super().__init__(message)
44+
self.ip_address = ip_address
45+
self.prefix_len = prefix_len
46+
47+
@property
48+
def network(self) -> Optional[Union[ipaddress.IPv4Network, ipaddress.IPv6Network]]:
49+
"""The network for the error"""
50+
51+
if self.ip_address is None or self.prefix_len is None:
52+
return None
53+
network = ipaddress.ip_network(f"{self.ip_address}/{self.prefix_len}", False)
54+
return network
2155

2256

2357
class AuthenticationError(GeoIP2Error):

0 commit comments

Comments
 (0)
0