Updates to PEP 3144 by Peter Moody.
This commit is contained in:
parent
fbc70cfb64
commit
ec3b9551ef
102
pep-3144.txt
102
pep-3144.txt
|
@ -84,29 +84,85 @@ Rationale:
|
||||||
While some network programmers will undoubtedly want more than this library
|
While some network programmers will undoubtedly want more than this library
|
||||||
provides, keeping the functionality to strictly what's required from a IP
|
provides, keeping the functionality to strictly what's required from a IP
|
||||||
address manipulation module is critical to keeping the code fast, easily
|
address manipulation module is critical to keeping the code fast, easily
|
||||||
comprehensible and extensible. It's important to note that this design
|
comprehensible and extensible. I've tried to provide enough options in
|
||||||
doesn't prevent subclassing or otherwise extending to meet the unforseen
|
terms of functionality to allow the developer to easily do their work
|
||||||
needs.
|
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:
|
Specification:
|
||||||
|
|
||||||
A slightly more detailed look at the library follows.
|
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.
|
- Multiple ways of displaying an IP Address.
|
||||||
|
|
||||||
Not everyone will want to display the same information in the same format;
|
Not everyone will want to display the same information in the same format;
|
||||||
IP addresses in cisco syntax are represented by network/hostmask, junipers
|
IP addresses in cisco syntax are represented by network/hostmask, junipers
|
||||||
are (network/IP)/prefixlength and IPTables are (network/IP)/(prefixlength/
|
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'
|
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'
|
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'
|
Out[1]: '1.1.1.1/0.0.0.0'
|
||||||
|
|
||||||
the same applies to IPv6
|
the same applies to IPv6
|
||||||
|
@ -123,7 +179,7 @@ Specification:
|
||||||
|
|
||||||
has a number of IPv4Address properties
|
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
|
In [2]: o.network
|
||||||
Out[2]: IPv4Address('1.1.1.0')
|
Out[2]: IPv4Address('1.1.1.0')
|
||||||
|
@ -144,7 +200,7 @@ Specification:
|
||||||
|
|
||||||
- Address list summarization.
|
- 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
|
addresses, as this is something network administrators constantly find
|
||||||
themselves doing. This currently works in a number of ways.
|
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
|
Given a list of networks, ipaddr will collapse the list into the smallest
|
||||||
possible list of networks that wholey contain the addresses supplied.
|
possible list of networks that wholey contain the addresses supplied.
|
||||||
|
|
||||||
In [1]: ipaddr.collapse_address_list([ipaddr.IP('1.1.0.0/24'),
|
In [1]: collapse_address_list([IPNetwork('1.1.0.0/24'),
|
||||||
...: ipaddr.IP('1.1.1.0/24')])
|
...: IPNetwork('1.1.1.0/24')])
|
||||||
Out[1]: [IPv4Network('1.1.0.0/23')]
|
Out[1]: [IPv4Network('1.1.0.0/23')]
|
||||||
|
|
||||||
more elaborately:
|
more elaborately:
|
||||||
|
|
||||||
In [1]: ipaddr.collapse_address_list([ipaddr.IP(x) \
|
In [1]: collapse_address_list([IPNetwork(x) for x in
|
||||||
...: for x in ipaddr.IP('1.1.0.0/23')])
|
...: IPNetwork('1.1.0.0/23')])
|
||||||
Out[1]: [IPv4Network('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
|
Given a start and end address, ipaddr will provide the smallest number of
|
||||||
networks to cover the given range.
|
networks to cover the given range.
|
||||||
|
|
||||||
|
|
||||||
In [1]: ipaddr.summarize_address_range(ipaddr.IPv4Address('1.1.1.0'),
|
In [1]: summarize_address_range(IPv4Address('1.1.1.0'),
|
||||||
...: ipaddr.IPv4Address('2.2.2.0'))
|
...: IPv4Address('2.2.2.0'))
|
||||||
Out[1]:
|
Out[1]:
|
||||||
[IPv4Network('1.1.1.0/24'),
|
[IPv4Network('1.1.1.0/24'),
|
||||||
IPv4Network('1.1.2.0/23'),
|
IPv4Network('1.1.2.0/23'),
|
||||||
|
@ -198,7 +254,7 @@ Specification:
|
||||||
ipaddr performs this exclusion equally well for IPv4 and IPv6 networks
|
ipaddr performs this exclusion equally well for IPv4 and IPv6 networks
|
||||||
and collapses the resulting address list.
|
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]:
|
Out[1]:
|
||||||
[IPv4Network('1.0.0.0/16'),
|
[IPv4Network('1.0.0.0/16'),
|
||||||
IPv4Network('1.1.0.0/24'),
|
IPv4Network('1.1.0.0/24'),
|
||||||
|
@ -210,7 +266,7 @@ Specification:
|
||||||
IPv4Network('1.1.64.0/18'),
|
IPv4Network('1.1.64.0/18'),
|
||||||
IPv4Network('1.1.128.0/17')]
|
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]:
|
Out[1]:
|
||||||
[IPv6Network('::1:0/112'),
|
[IPv6Network('::1:0/112'),
|
||||||
IPv6Network('::2:0/111'),
|
IPv6Network('::2:0/111'),
|
||||||
|
@ -235,16 +291,16 @@ Specification:
|
||||||
BaseV6._compress_hextets), but ipaddr makes both the compressed and the
|
BaseV6._compress_hextets), but ipaddr makes both the compressed and the
|
||||||
exploded representations available.
|
exploded representations available.
|
||||||
|
|
||||||
In [1]: ipaddr.IP('::1').compressed
|
In [1]: IPNetwork('::1').compressed
|
||||||
Out[1]: '::1/128'
|
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'
|
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'
|
Out[3]: '0000:0000:0000:0000:0000:0000:0000:0001'
|
||||||
|
|
||||||
In [4]: ipaddr.IPv6Address('::1').compressed
|
In [4]: IPv6Address('::1').compressed
|
||||||
Out[4]: '::1'
|
Out[4]: '::1'
|
||||||
|
|
||||||
(the same methods exist for IPv4 networks and addresses, but they're
|
(the same methods exist for IPv4 networks and addresses, but they're
|
||||||
|
@ -260,7 +316,7 @@ Reference Implementation:
|
||||||
References:
|
References:
|
||||||
|
|
||||||
[1] http://bugs.python.org/issue3959
|
[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
|
[3] http://codereview.appspot.com/110044
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue