Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit b582ecc

Browse files
committed
Issue 14814: Explain how to get more error detail in the ipaddress tutorial, and tweak the display for octet errors in IPv4 (noticed the formatting problem when adding to the docs)
1 parent 01ac8b6 commit b582ecc

3 files changed

Lines changed: 43 additions & 16 deletions

File tree

Doc/howto/ipaddress.rst

Lines changed: 37 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -277,23 +277,49 @@ an integer or string that the other module will accept::
277277
3221225985
278278

279279

280-
Exceptions raised by :mod:`ipaddress`
281-
=====================================
280+
Getting more detail when instance creation fails
281+
================================================
282282

283283
When creating address/network/interface objects using the version-agnostic
284-
factory functions, any errors will be reported as :exc:`ValueError`.
284+
factory functions, any errors will be reported as :exc:`ValueError` with
285+
a generic error message that simply says the passed in value was not
286+
recognised as an object of that type. The lack of a specific error is
287+
because it's necessary to know whether the value is *supposed* to be IPv4
288+
or IPv6 in order to provide more detail on why it has been rejected.
289+
290+
To support use cases where it is useful to have access to this additional
291+
detail, the individual class constructors actually raise the
292+
:exc:`ValueError` subclasses :exc:`ipaddress.AddressValueError` and
293+
:exc:`ipaddress.NetmaskValueError` to indicate exactly which part of
294+
the definition failed to parse correctly.
295+
296+
The error messages are significantly more detailed when using the
297+
class constructors directly. For example::
298+
299+
>>> ipaddress.ip_address("192.168.0.256")
300+
Traceback (most recent call last):
301+
...
302+
ValueError: '192.168.0.256' does not appear to be an IPv4 or IPv6 address
303+
>>> ipaddress.IPv4Address("192.168.0.256")
304+
Traceback (most recent call last):
305+
...
306+
ipaddress.AddressValueError: Octet 256 (> 255) not permitted in '192.168.0.256'
285307

286-
For some use cases, it desirable to know whether it is the address or the
287-
netmask which is incorrect. To support these use cases, the class
288-
constructors actually raise the :exc:`ValueError` subclasses
289-
:exc:`ipaddress.AddressValueError` and :exc:`ipaddress.NetmaskValueError`
290-
to indicate exactly which part of the definition failed to parse correctly.
308+
>>> ipaddress.ip_network("192.168.0.1/64")
309+
Traceback (most recent call last):
310+
...
311+
ValueError: '192.168.0.1/64' does not appear to be an IPv4 or IPv6 network
312+
>>> ipaddress.IPv4Network("192.168.0.1/64")
313+
Traceback (most recent call last):
314+
...
315+
ipaddress.NetmaskValueError: '64' is not a valid netmask
291316

292-
Both of the module specific exceptions have :exc:`ValueError` as their
317+
However, both of the module specific exceptions have :exc:`ValueError` as their
293318
parent class, so if you're not concerned with the particular type of error,
294319
you can still write code like the following::
295320

296321
try:
297-
ipaddress.IPv4Address(address)
322+
network = ipaddress.IPv4Network(address)
298323
except ValueError:
299-
print('address/netmask is invalid:', address)
324+
print('address/netmask is invalid for IPv4:', address)
325+

Lib/ipaddress.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1048,7 +1048,7 @@ def _parse_octet(self, octet_str):
10481048
raise ValueError("Ambiguous leading zero in %r not permitted" %
10491049
octet_str)
10501050
if octet_int > 255:
1051-
raise ValueError("Octet %d > 255 not permitted" % octet_int)
1051+
raise ValueError("Octet %d (> 255) not permitted" % octet_int)
10521052
return octet_int
10531053

10541054
def _string_from_ip_int(self, ip_int):
@@ -1591,7 +1591,8 @@ def _parse_hextet(self, hextet_str):
15911591
hextet_int = int(hextet_str, 16)
15921592
if hextet_int > 0xFFFF:
15931593
# This is unreachable due to the string length check above
1594-
raise ValueError("Part %d > 0xFFFF not permitted" % hextet_int)
1594+
msg = "Part 0x%X (> 0xFFFF) not permitted"
1595+
raise ValueError(msg % hextet_int)
15951596
return hextet_int
15961597

15971598
def _compress_hextets(self, hextets):

Lib/test/test_ipaddress.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -126,8 +126,8 @@ def assertBadOctet(addr, octet):
126126

127127
def test_octet_limit(self):
128128
def assertBadOctet(addr, octet):
129-
msg = "Octet %d > 255 not permitted in %r"
130-
with self.assertAddressError(msg, octet, addr):
129+
msg = "Octet %d (> 255) not permitted in %r" % (octet, addr)
130+
with self.assertAddressError(re.escape(msg)):
131131
ipaddress.IPv4Address(addr)
132132

133133
assertBadOctet("12345.67899.-54321.-98765", 12345)
@@ -310,7 +310,7 @@ def assertBadAddress(addr, details):
310310
assertBadAddress("google.com", "Expected 4 octets")
311311
assertBadAddress("10/8", "Expected 4 octets")
312312
assertBadAddress("::1.2.3.4", "Only decimal digits")
313-
assertBadAddress("1.2.3.256", "256 > 255")
313+
assertBadAddress("1.2.3.256", re.escape("256 (> 255)"))
314314

315315
def test_netmask_errors(self):
316316
def assertBadNetmask(addr, netmask):

0 commit comments

Comments
 (0)