From ec3b9551ef2b76aecc0151df86e5c6459908285d Mon Sep 17 00:00:00 2001 From: Brett Cannon Date: Thu, 27 Aug 2009 22:51:15 +0000 Subject: [PATCH] Updates to PEP 3144 by Peter Moody. --- pep-3144.txt | 102 +++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 79 insertions(+), 23 deletions(-) diff --git a/pep-3144.txt b/pep-3144.txt index 096413de4..f5616a82c 100644 --- a/pep-3144.txt +++ b/pep-3144.txt @@ -84,29 +84,85 @@ Rationale: While some network programmers will undoubtedly want more than this library provides, keeping the functionality to strictly what's required from a IP address manipulation module is critical to keeping the code fast, easily - comprehensible and extensible. It's important to note that this design - doesn't prevent subclassing or otherwise extending to meet the unforseen - needs. + comprehensible and extensible. I've tried to provide enough options in + terms of functionality to allow the developer to easily do their work + without needlessly cluttering the library. Finally, It's important to note + that this design doesn't prevent subclassing or otherwise extending to meet + the unforeseen needs. Specification: A slightly more detailed look at the library follows. + - Design + + ipaddr has four main classes most people will use: + + 1. IPv4Address. (eg, '192.168.1.1') + 2. IPv4Network (eg, '192.168.0.0/16') + 3. IPv6Address (eg, '::1') + 4. IPv6Network (eg, '2001::/32') + + Most of the operations a network administrator performs on networks are + similar for both IPv4 and IPv6 networks. Ie. finding subnets, supernets, + determining if an address is contained in a given network, etc. Similarly, + both addresses and networks (of the same ip version!) have much in common; + the process for turning a given 32 or 128 bit number into a human readable + string notation, determining if the ip is within the valid specified range, + etc. Finally, there are some pythonic abstractions which are valid for all + addresses and networks, both IPv4 and IPv6. In short, there is common + functionality shared between (ipaddr class names in parentheses): + + 1. all IP addresses and networks, both IPv4 and IPv6. (IPAddrBase) + + 2. all IP addresses of both versions. (BaseIP) + + 3. all IP networks of both version. (BaseNet) + + 4. all IPv4 objects, both addresses and networks. (BaseV4) + + 5. all IPv6 objects, both addresses and networks. (BaseV6) + + Seeing this as a clear hierarchy is important for recognizing how much + code is common between the four main classes. For this reason, ipaddr uses + class inheritance to abstract out as much common code is possible and + appropriate. This lack of duplication and very clean layout also makes + the job of the developer much easier should they need to debug code (either + theirs or mine). + + Knowing that there might be cases where the developer doesn't so much care + as to the types of IP they might be receiving, ipaddr comes with two + important helper functions, IPAddress() and IPNetwork(). These, as you + might guess, return the appropriately typed address or network objects for + the given argument. + + Finally, this distinction between IPv4 and IPv6 IP versions means that + comparison operations on them return TypeError for py3k per Ordering + Comparisons [2]. In practice, this shouldn't pose a problem for the + developer who can easily write: + + v4 = [x for x in mixed_list if x._version == 4] + v6 = [x for x in mixed_list if x._version == 6] + + # perform operations on v4 and v6 here. + + return v4_return + v6_return + - Multiple ways of displaying an IP Address. Not everyone will want to display the same information in the same format; IP addresses in cisco syntax are represented by network/hostmask, junipers are (network/IP)/prefixlength and IPTables are (network/IP)/(prefixlength/ - netmask). The ipaddr library provides mulitple ways to display an address. + netmask). The ipaddr library provides multiple ways to display an address. - In [1]: ipaddr.IP('1.1.1.1').with_prefixlen + In [1]: IPNetwork('1.1.1.1').with_prefixlen Out[1]: '1.1.1.1/32' - In [1]: ipaddr.IP('1.1.1.1').with_netmask + In [1]: IPNetwork('1.1.1.1').with_netmask Out[1]: '1.1.1.1/255.255.255.255' - In [1]: ipaddr.IP('1.1.1.1').with_hostmask + In [1]: IPNetwork('1.1.1.1').with_hostmask Out[1]: '1.1.1.1/0.0.0.0' the same applies to IPv6 @@ -123,7 +179,7 @@ Specification: has a number of IPv4Address properties - In [1]: o = ipaddr.IPv4Network('1.1.1.0/24') + In [1]: o = IPv4Network('1.1.1.0/24') In [2]: o.network Out[2]: IPv4Address('1.1.1.0') @@ -144,7 +200,7 @@ Specification: - Address list summarization. - ipaddr supports easy summarization of lists of possibly contigious + ipaddr supports easy summarization of lists of possibly contiguous addresses, as this is something network administrators constantly find themselves doing. This currently works in a number of ways. @@ -153,24 +209,24 @@ Specification: Given a list of networks, ipaddr will collapse the list into the smallest possible list of networks that wholey contain the addresses supplied. - In [1]: ipaddr.collapse_address_list([ipaddr.IP('1.1.0.0/24'), - ...: ipaddr.IP('1.1.1.0/24')]) + In [1]: collapse_address_list([IPNetwork('1.1.0.0/24'), + ...: IPNetwork('1.1.1.0/24')]) Out[1]: [IPv4Network('1.1.0.0/23')] more elaborately: - In [1]: ipaddr.collapse_address_list([ipaddr.IP(x) \ - ...: for x in ipaddr.IP('1.1.0.0/23')]) + In [1]: collapse_address_list([IPNetwork(x) for x in + ...: IPNetwork('1.1.0.0/23')]) Out[1]: [IPv4Network('1.1.0.0/23')] - 2. summarize_address_range(first, last). (in a pending change list [2]) + 2. summarize_address_range(first, last). Given a start and end address, ipaddr will provide the smallest number of networks to cover the given range. - In [1]: ipaddr.summarize_address_range(ipaddr.IPv4Address('1.1.1.0'), - ...: ipaddr.IPv4Address('2.2.2.0')) + In [1]: summarize_address_range(IPv4Address('1.1.1.0'), + ...: IPv4Address('2.2.2.0')) Out[1]: [IPv4Network('1.1.1.0/24'), IPv4Network('1.1.2.0/23'), @@ -198,7 +254,7 @@ Specification: ipaddr performs this exclusion equally well for IPv4 and IPv6 networks and collapses the resulting address list. - In [1]: ipaddr.IP('1.1.0.0/15').address_exclude(ipaddr.IP('1.1.1.0/24')) + In [1]: IPNetwork('1.1.0.0/15').address_exclude(IPNetwork('1.1.1.0/24')) Out[1]: [IPv4Network('1.0.0.0/16'), IPv4Network('1.1.0.0/24'), @@ -210,7 +266,7 @@ Specification: IPv4Network('1.1.64.0/18'), IPv4Network('1.1.128.0/17')] - In [1]: ipaddr.IP('::1/96').address_exclude(ipaddr.IP('::1/112')) + In [1]: IPNewtork('::1/96').address_exclude(IPNetwork('::1/112')) Out[1]: [IPv6Network('::1:0/112'), IPv6Network('::2:0/111'), @@ -235,16 +291,16 @@ Specification: BaseV6._compress_hextets), but ipaddr makes both the compressed and the exploded representations available. - In [1]: ipaddr.IP('::1').compressed + In [1]: IPNetwork('::1').compressed Out[1]: '::1/128' - In [2]: ipaddr.IP('::1').exploded + In [2]: IPNetwork('::1').exploded Out[2]: '0000:0000:0000:0000:0000:0000:0000:1/128' - In [3]: ipaddr.IPv6Address('::1').exploded + In [3]: IPv6Address('::1').exploded Out[3]: '0000:0000:0000:0000:0000:0000:0000:0001' - In [4]: ipaddr.IPv6Address('::1').compressed + In [4]: IPv6Address('::1').compressed Out[4]: '::1' (the same methods exist for IPv4 networks and addresses, but they're @@ -260,7 +316,7 @@ Reference Implementation: References: [1] http://bugs.python.org/issue3959 - [2] http://codereview.appspot.com/67107 + [2] http://docs.python.org/dev/3.0/whatsnew/3.0.html#ordering-comparisons [3] http://codereview.appspot.com/110044