summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNick Coghlan <ncoghlan@gmail.com>2012-07-07 12:15:22 (GMT)
committerNick Coghlan <ncoghlan@gmail.com>2012-07-07 12:15:22 (GMT)
commitb582ecc562b0a4c00e2d9fe39f42d22dd9c7f89e (patch)
tree72bf2ff495e65ebaa48c677a62e70ecebb783810
parent01ac8b6ab1474d863f364b6c11eb9fce62324169 (diff)
downloadcpython-b582ecc562b0a4c00e2d9fe39f42d22dd9c7f89e.zip
cpython-b582ecc562b0a4c00e2d9fe39f42d22dd9c7f89e.tar.gz
cpython-b582ecc562b0a4c00e2d9fe39f42d22dd9c7f89e.tar.bz2
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)
-rw-r--r--Doc/howto/ipaddress.rst48
-rw-r--r--Lib/ipaddress.py5
-rw-r--r--Lib/test/test_ipaddress.py6
3 files changed, 43 insertions, 16 deletions
diff --git a/Doc/howto/ipaddress.rst b/Doc/howto/ipaddress.rst
index 4d9ca08..67cf763 100644
--- a/Doc/howto/ipaddress.rst
+++ b/Doc/howto/ipaddress.rst
@@ -277,23 +277,49 @@ an integer or string that the other module will accept::
3221225985
-Exceptions raised by :mod:`ipaddress`
-=====================================
+Getting more detail when instance creation fails
+================================================
When creating address/network/interface objects using the version-agnostic
-factory functions, any errors will be reported as :exc:`ValueError`.
+factory functions, any errors will be reported as :exc:`ValueError` with
+a generic error message that simply says the passed in value was not
+recognised as an object of that type. The lack of a specific error is
+because it's necessary to know whether the value is *supposed* to be IPv4
+or IPv6 in order to provide more detail on why it has been rejected.
+
+To support use cases where it is useful to have access to this additional
+detail, the individual class constructors actually raise the
+:exc:`ValueError` subclasses :exc:`ipaddress.AddressValueError` and
+:exc:`ipaddress.NetmaskValueError` to indicate exactly which part of
+the definition failed to parse correctly.
+
+The error messages are significantly more detailed when using the
+class constructors directly. For example::
+
+ >>> ipaddress.ip_address("192.168.0.256")
+ Traceback (most recent call last):
+ ...
+ ValueError: '192.168.0.256' does not appear to be an IPv4 or IPv6 address
+ >>> ipaddress.IPv4Address("192.168.0.256")
+ Traceback (most recent call last):
+ ...
+ ipaddress.AddressValueError: Octet 256 (> 255) not permitted in '192.168.0.256'
-For some use cases, it desirable to know whether it is the address or the
-netmask which is incorrect. To support these use cases, the class
-constructors actually raise the :exc:`ValueError` subclasses
-:exc:`ipaddress.AddressValueError` and :exc:`ipaddress.NetmaskValueError`
-to indicate exactly which part of the definition failed to parse correctly.
+ >>> ipaddress.ip_network("192.168.0.1/64")
+ Traceback (most recent call last):
+ ...
+ ValueError: '192.168.0.1/64' does not appear to be an IPv4 or IPv6 network
+ >>> ipaddress.IPv4Network("192.168.0.1/64")
+ Traceback (most recent call last):
+ ...
+ ipaddress.NetmaskValueError: '64' is not a valid netmask
-Both of the module specific exceptions have :exc:`ValueError` as their
+However, both of the module specific exceptions have :exc:`ValueError` as their
parent class, so if you're not concerned with the particular type of error,
you can still write code like the following::
try:
- ipaddress.IPv4Address(address)
+ network = ipaddress.IPv4Network(address)
except ValueError:
- print('address/netmask is invalid:', address)
+ print('address/netmask is invalid for IPv4:', address)
+
diff --git a/Lib/ipaddress.py b/Lib/ipaddress.py
index bd79e2a..e788c0a5 100644
--- a/Lib/ipaddress.py
+++ b/Lib/ipaddress.py
@@ -1048,7 +1048,7 @@ class _BaseV4:
raise ValueError("Ambiguous leading zero in %r not permitted" %
octet_str)
if octet_int > 255:
- raise ValueError("Octet %d > 255 not permitted" % octet_int)
+ raise ValueError("Octet %d (> 255) not permitted" % octet_int)
return octet_int
def _string_from_ip_int(self, ip_int):
@@ -1591,7 +1591,8 @@ class _BaseV6:
hextet_int = int(hextet_str, 16)
if hextet_int > 0xFFFF:
# This is unreachable due to the string length check above
- raise ValueError("Part %d > 0xFFFF not permitted" % hextet_int)
+ msg = "Part 0x%X (> 0xFFFF) not permitted"
+ raise ValueError(msg % hextet_int)
return hextet_int
def _compress_hextets(self, hextets):
diff --git a/Lib/test/test_ipaddress.py b/Lib/test/test_ipaddress.py
index 61ec0d6..2ac37e1 100644
--- a/Lib/test/test_ipaddress.py
+++ b/Lib/test/test_ipaddress.py
@@ -126,8 +126,8 @@ class AddressErrors_v4(ErrorReporting):
def test_octet_limit(self):
def assertBadOctet(addr, octet):
- msg = "Octet %d > 255 not permitted in %r"
- with self.assertAddressError(msg, octet, addr):
+ msg = "Octet %d (> 255) not permitted in %r" % (octet, addr)
+ with self.assertAddressError(re.escape(msg)):
ipaddress.IPv4Address(addr)
assertBadOctet("12345.67899.-54321.-98765", 12345)
@@ -310,7 +310,7 @@ class NetmaskErrorsMixin_v4:
assertBadAddress("google.com", "Expected 4 octets")
assertBadAddress("10/8", "Expected 4 octets")
assertBadAddress("::1.2.3.4", "Only decimal digits")
- assertBadAddress("1.2.3.256", "256 > 255")
+ assertBadAddress("1.2.3.256", re.escape("256 (> 255)"))
def test_netmask_errors(self):
def assertBadNetmask(addr, netmask):