Updates to PEP 3144 by Peter Moody.

This commit is contained in:
Brett Cannon 2009-08-27 22:51:15 +00:00
parent fbc70cfb64
commit ec3b9551ef
1 changed files with 79 additions and 23 deletions

View File

@ -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