Update from Peter.
This commit is contained in:
parent
4b8dac5847
commit
fbc70cfb64
202
pep-3144.txt
202
pep-3144.txt
|
@ -66,44 +66,6 @@ Rationale:
|
||||||
property addresses in an IP network obviously don't have the same
|
property addresses in an IP network obviously don't have the same
|
||||||
properties, they're simply 32 or 128 bit numbers.
|
properties, they're simply 32 or 128 bit numbers.
|
||||||
|
|
||||||
- Lazy evaluation combined with aggressive caching of network elements.
|
|
||||||
|
|
||||||
(the following example is for IPv6Network objects but the exact same
|
|
||||||
properties apply to IPv6Network objects).
|
|
||||||
|
|
||||||
As mentioned, an IP network object is defined by a number of properties.
|
|
||||||
The object
|
|
||||||
|
|
||||||
>>> IPv4Network('1.1.1.0/24')
|
|
||||||
|
|
||||||
has a number of IPv4Address properties
|
|
||||||
|
|
||||||
>>> o = ipaddr.IPv4Network('1.1.1.0/24')
|
|
||||||
|
|
||||||
>>> o.network
|
|
||||||
IPv4Address('1.1.1.0')
|
|
||||||
|
|
||||||
>>> o.broadcast
|
|
||||||
IPv4Address('1.1.1.255')
|
|
||||||
|
|
||||||
>>> o.network
|
|
||||||
IPv4Address('1.1.1.0')
|
|
||||||
|
|
||||||
>>> o.hostmask
|
|
||||||
IPv4Address('0.0.0.255')
|
|
||||||
|
|
||||||
If we were to compute them all at object creation time, we would incur a
|
|
||||||
non-negligible performance hit. Since these properties are required to
|
|
||||||
define the object completely but their values aren't always of interest to
|
|
||||||
the programmer, their computation should be done only when requested.
|
|
||||||
However, in order to avoid the performance hit in the case where one
|
|
||||||
attribute for a particular object is requested repeatedly (and continuously
|
|
||||||
recomputed), the results of the first computation should be cached and only
|
|
||||||
re-generated should the object properties change. The network properties
|
|
||||||
would change if, for instance, the prefix length was changed, resulting in
|
|
||||||
either a larger (decreasing prefix length) or a smaller (increasing prefix
|
|
||||||
length) network.
|
|
||||||
|
|
||||||
- Treat network elements as lists (in so far as it's possible).
|
- Treat network elements as lists (in so far as it's possible).
|
||||||
|
|
||||||
Treating IP networks as lists is a natural extension from viewing the
|
Treating IP networks as lists is a natural extension from viewing the
|
||||||
|
@ -127,6 +89,168 @@ Rationale:
|
||||||
needs.
|
needs.
|
||||||
|
|
||||||
|
|
||||||
|
Specification:
|
||||||
|
|
||||||
|
A slightly more detailed look at the library follows.
|
||||||
|
|
||||||
|
- 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.
|
||||||
|
|
||||||
|
In [1]: ipaddr.IP('1.1.1.1').with_prefixlen
|
||||||
|
Out[1]: '1.1.1.1/32'
|
||||||
|
|
||||||
|
In [1]: ipaddr.IP('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
|
||||||
|
Out[1]: '1.1.1.1/0.0.0.0'
|
||||||
|
|
||||||
|
the same applies to IPv6
|
||||||
|
|
||||||
|
- Lazy evaluation combined with aggressive caching of network elements.
|
||||||
|
|
||||||
|
(the following example is for IPv6Network objects but the exact same
|
||||||
|
properties apply to IPv6Network objects).
|
||||||
|
|
||||||
|
As mentioned, an IP network object is defined by a number of properties.
|
||||||
|
The object
|
||||||
|
|
||||||
|
In [1]: IPv4Network('1.1.1.0/24')
|
||||||
|
|
||||||
|
has a number of IPv4Address properties
|
||||||
|
|
||||||
|
In [1]: o = ipaddr.IPv4Network('1.1.1.0/24')
|
||||||
|
|
||||||
|
In [2]: o.network
|
||||||
|
Out[2]: IPv4Address('1.1.1.0')
|
||||||
|
|
||||||
|
In [3]: o.broadcast
|
||||||
|
Out[3]: IPv4Address('1.1.1.255')
|
||||||
|
|
||||||
|
In [4]: o.hostmask
|
||||||
|
Out[4]: IPv4Address('0.0.0.255')
|
||||||
|
|
||||||
|
If we were to compute them all at object creation time, we would incur a
|
||||||
|
non-negligible performance hit. Since these properties are required to
|
||||||
|
define the object completely but their values aren't always of interest to
|
||||||
|
the programmer, their computation should be done only when requested.
|
||||||
|
However, in order to avoid the performance hit in the case where one
|
||||||
|
attribute for a particular object is requested repeatedly (and continuously
|
||||||
|
recomputed), the results of the computation should be cached.
|
||||||
|
|
||||||
|
- Address list summarization.
|
||||||
|
|
||||||
|
ipaddr supports easy summarization of lists of possibly contigious
|
||||||
|
addresses, as this is something network administrators constantly find
|
||||||
|
themselves doing. This currently works in a number of ways.
|
||||||
|
|
||||||
|
1. collapse_address_list([list]):
|
||||||
|
|
||||||
|
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')])
|
||||||
|
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')])
|
||||||
|
Out[1]: [IPv4Network('1.1.0.0/23')]
|
||||||
|
|
||||||
|
2. summarize_address_range(first, last). (in a pending change list [2])
|
||||||
|
|
||||||
|
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'))
|
||||||
|
Out[1]:
|
||||||
|
[IPv4Network('1.1.1.0/24'),
|
||||||
|
IPv4Network('1.1.2.0/23'),
|
||||||
|
IPv4Network('1.1.4.0/22'),
|
||||||
|
IPv4Network('1.1.8.0/21'),
|
||||||
|
IPv4Network('1.1.16.0/20'),
|
||||||
|
IPv4Network('1.1.32.0/19'),
|
||||||
|
IPv4Network('1.1.64.0/18'),
|
||||||
|
IPv4Network('1.1.128.0/17'),
|
||||||
|
IPv4Network('1.2.0.0/15'),
|
||||||
|
IPv4Network('1.4.0.0/14'),
|
||||||
|
IPv4Network('1.8.0.0/13'),
|
||||||
|
IPv4Network('1.16.0.0/12'),
|
||||||
|
IPv4Network('1.32.0.0/11'),
|
||||||
|
IPv4Network('1.64.0.0/10'),
|
||||||
|
IPv4Network('1.128.0.0/9'),
|
||||||
|
IPv4Network('2.0.0.0/15'),
|
||||||
|
IPv4Network('2.2.0.0/23'),
|
||||||
|
IPv4Network('2.2.2.0/32')]
|
||||||
|
|
||||||
|
- Address Exclusion.
|
||||||
|
|
||||||
|
Used somewhat less often, but all the more annoying, is the case where an
|
||||||
|
programmer would want "all of the addresses in a newtork *except* these".
|
||||||
|
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'))
|
||||||
|
Out[1]:
|
||||||
|
[IPv4Network('1.0.0.0/16'),
|
||||||
|
IPv4Network('1.1.0.0/24'),
|
||||||
|
IPv4Network('1.1.2.0/23'),
|
||||||
|
IPv4Network('1.1.4.0/22'),
|
||||||
|
IPv4Network('1.1.8.0/21'),
|
||||||
|
IPv4Network('1.1.16.0/20'),
|
||||||
|
IPv4Network('1.1.32.0/19'),
|
||||||
|
IPv4Network('1.1.64.0/18'),
|
||||||
|
IPv4Network('1.1.128.0/17')]
|
||||||
|
|
||||||
|
In [1]: ipaddr.IP('::1/96').address_exclude(ipaddr.IP('::1/112'))
|
||||||
|
Out[1]:
|
||||||
|
[IPv6Network('::1:0/112'),
|
||||||
|
IPv6Network('::2:0/111'),
|
||||||
|
IPv6Network('::4:0/110'),
|
||||||
|
IPv6Network('::8:0/109'),
|
||||||
|
IPv6Network('::10:0/108'),
|
||||||
|
IPv6Network('::20:0/107'),
|
||||||
|
IPv6Network('::40:0/106'),
|
||||||
|
IPv6Network('::80:0/105'),
|
||||||
|
IPv6Network('::100:0/104'),
|
||||||
|
IPv6Network('::200:0/103'),
|
||||||
|
IPv6Network('::400:0/102'),
|
||||||
|
IPv6Network('::800:0/101'),
|
||||||
|
IPv6Network('::1000:0/100'),
|
||||||
|
IPv6Network('::2000:0/99'),
|
||||||
|
IPv6Network('::4000:0/98'),
|
||||||
|
IPv6Network('::8000:0/97')]
|
||||||
|
|
||||||
|
- IPv6 address compression. (in a pending changelist [3])
|
||||||
|
|
||||||
|
By default, IPv6 addresses are compressed internally (see the method
|
||||||
|
BaseV6._compress_hextets), but ipaddr makes both the compressed and the
|
||||||
|
exploded representations available.
|
||||||
|
|
||||||
|
In [1]: ipaddr.IP('::1').compressed
|
||||||
|
Out[1]: '::1/128'
|
||||||
|
|
||||||
|
In [2]: ipaddr.IP('::1').exploded
|
||||||
|
Out[2]: '0000:0000:0000:0000:0000:0000:0000:1/128'
|
||||||
|
|
||||||
|
In [3]: ipaddr.IPv6Address('::1').exploded
|
||||||
|
Out[3]: '0000:0000:0000:0000:0000:0000:0000:0001'
|
||||||
|
|
||||||
|
In [4]: ipaddr.IPv6Address('::1').compressed
|
||||||
|
Out[4]: '::1'
|
||||||
|
|
||||||
|
(the same methods exist for IPv4 networks and addresses, but they're
|
||||||
|
just stubs for returning the normal __str__ representation).
|
||||||
|
|
||||||
|
|
||||||
Reference Implementation:
|
Reference Implementation:
|
||||||
|
|
||||||
A reference implementation is available at:
|
A reference implementation is available at:
|
||||||
|
@ -136,6 +260,8 @@ Reference Implementation:
|
||||||
References:
|
References:
|
||||||
|
|
||||||
[1] http://bugs.python.org/issue3959
|
[1] http://bugs.python.org/issue3959
|
||||||
|
[2] http://codereview.appspot.com/67107
|
||||||
|
[3] http://codereview.appspot.com/110044
|
||||||
|
|
||||||
|
|
||||||
Copyright:
|
Copyright:
|
||||||
|
|
Loading…
Reference in New Issue