[Python-Dev] PEP 3144: IP Address Manipulation Library for the Python Standard Library
drkjam at gmail.com
Tue Aug 25 00:24:48 CEST 2009
Good evening fellow Pythonistas,
Considering a PEP is now available I'd like to join this discussion and
raise several points with regard to both the PEP and the ipaddr reference
implementation put forward with it.
1) Firstly, an offering of code.
I'd like to bring to your attention an example implementation of an IP
address library and interface for general discussion to compare and contrast
with ipaddr 2.0.x :-
It is based on netaddr 0.7.2 which I threw together earlier today.
In essence, I've stripped out all of what could be considered non-essential
code for a purely IP related library. This branch should be suitable for
*theoretical* consideration of inclusion into some future version of the
Python standard library (with a little work).
It is a pure subset of netaddr release 0.7.2, *minus* the following :-
- all IEEE layer-2 code
- some fairly non-essential IANA IP data files and lookup code
- IP globbing code (fairly niche)
Aside: Just a small mention here that I listened carefully to Clay McClure's
and others criticisms of the previous incarnation of ipaddr. The 0.7.x
series of netaddr breaks backward compatibility with previous netaddr
releases and is an "answer" of sorts to that discussion and issue raised
within the Python community. I hope you like what I've done with it.
For the purposes of this discussion consider this branch the "Firefox to
netaddr's Mozilla" or maybe just plain old "netaddr-ip-lite" ;-)
2) I refute bold claim in the PEP that :-
"Finding a good library for performing those tasks can be somewhat more
On the contrary, I wager that netaddr is now a perfectly decent alternative
implementation to ipaddr, containing quite a few more features with little
of the slowness for most common operations, 2/3x faster in a lot of cases,
not that we're counting. What a difference a year makes! I also rate IPy
quite highly even if it is getting a little "long in the tooth". For a lot
of users, IPy could also be considered a nice, stable API!
By the same token I'm happy to note some convergence between the ipaddr and
netaddr's various interfaces, particularly in light of discussions and
arguments put forward by Clay McClure and others. A satisfactory compromise
between the two however still seems a way off.
3) I also disagree with the PEP's claim that :-
"attempts to combine [IPv4 and IPv6] into one object would be like
trying to force a round peg into a square hole (or vice versa)".
netaddr (and for that matter IPy) cope with this perceived problem
netaddr employs a simple variant of the GoF Strategy design pattern (with
added Python sensibility). In the rare cases where ambiguity exists between
IPv4 and IPv6 addresses a version parameter may be passed to the constructor
of the IPAddress class to differentiate between them. Providing an IP
address version to the constructor also provides a small performance
IPv4 and IPv6 addresses can be used interchangably throughout netaddr
without causing issue during operations such as sorting, merging (known in
the PEP as "address collapsing") or address exclusion.
Don't try and do this with the current reference implementation of ipaddr :-
OUCH! Even if this isn't allowed (according to the documentation), it should
raise an Exception rather than silently passing through.
I actually raised this back in May on the ipaddr bug tracker but it hasn't
received any attention so far :-
Compare this with netaddr's behaviour :-
>>> cidr_merge([IPAddress('220.127.116.11'), IPAddress('::18.104.22.168')])
That's more like it.
4) It may just be me but the design of this latest incarnation of ipaddr
seems somewhat complicated for so few lines of code. Compared with ipaddr,
netaddr doesn't use or require multiple inheritance nor a seemingly
convoluted inheritance heirarchy. There isn't a need for an IP() type
'multiplexer' function either (although I might be missing an important use
case here). But, then again, this may just be my personal preference talking
here. I prefer composition over inheritance in most cases.
In netaddr, if a user wants to represent an IP address (without netmask),
they should use the IPAddress class, if they want to represent and IP
address with some form of mask, they should use the IPNetwork class.
5) The ipaddr library is also missing options for expanding various
(exceedingly common) IP abbreviations.
>>> from netaddr import IPNetwork
>>> IPNetwork('10/8', True)
netaddr also handles classful IP address logic, still pervasive throughout
modern IP stacks :-
>>> IPNetwork('192.168.0.1', True)
Note that these options are disabled by default, to keep up the speed of the
IPNetwork constructor up for more normal cases.
6) netaddr currently contains a lot of useful features absent in ipaddr that
would be extremely useful in a general, "lightweight" IP library.
For example, it already contains routines for :-
- arbitrary address range calculations
- full assistance for IPv4-mapped/compatible IPv6 addressing
- a fully function IPSet class which allows you to perform operations such
as unions, intersections and symmetric differences between lists of
IPNetwork (CIDR) objects.
The last one is actually really handy and is based on an idea for an IPv4
only library by Heiko Wundram posted to the ASPN Python Cookbook some years
ago (details can be found in the netaddr THANKS file).
There is a lot more to consider here than I can cram into this initial
message, so I'll hand over to you all for some (hopefully) serious debate.
David P. D. Moss
netaddr author and maintainer
PS - Why does the References section in the PEP contain links to patches
already applied to the ipaddr 2.0.x reference implementation?
-------------- next part --------------
An HTML attachment was scrubbed...
More information about the Python-Dev