[Python-Dev] Issues with Py3.1's new ipaddr

R. David Murray rdmurray at bitdance.com
Tue Jun 2 22:53:16 CEST 2009


On Tue, 2 Jun 2009 at 12:26, Clay McClure wrote:
> On Tue, Jun 2, 2009 at 2:08 AM, "Martin v. Löwis" <martin at v.loewis.de> wrote:
>> py> x = ipaddr.IP("30.40.50.60")
>> py> print(x.ip_ext_full)
>> 30.40.50.60
>
> Thankfully the authors have provided this obscure and strangely-named
> method to get at the correct string representation of an IP address,
> but sadly their __str__ method -- which is the Pythonic way to get
> string representations of objects -- fails in this regard because they
> have only one class representing two distinct concepts.

Having thought more about this, I will agree with you that it would
be useful to have an address-without-netmask class. I'm thinking about
the cases where having an attached netmask is not particularly helpful,
for example in DNS entries.  But there are only two reasons I've so far
come up with why this would be useful:  to have a different default output
format, and to have a way to encode an IP so that I can have my code raise
an error if I try to use it in a context where a netmask is required.
(Note, however, that even a DNS entry can conceptually be considered to
be a host route.)

IMO, not having such a class is an inconvenience, not a show stopper,
especially since it seems like one could be added without breaking
backward compatibility.  I also don't particularly like the names of
the ipaddr attributes for accessing the IP address-without-netmask or
the netmask-without-ip-address, etc; but again, I don't consider that
a show stopper.

So I'm not in favor of pulling ipaddr from 3.1, and it's too late in
the release cycle to change anything.

I wish you had brought this energy to bear earlier, when changes could
have been made.  Reality is what it is, though, and now we should work
on making improvements for the next release.  I see in the ticket that
the netaddr folks were going to propose improvements so that they could
build netaddr on top of ipaddr, but I guess that didn't happen (yet?).

I have no association with Google, by the way, and I do intend to use
ipaddr in upcoming code, and have hacked my own address manipulation
stuff in previous code.

>>> Such notation is unacceptable in
>>> real-world applications that (correctly) distinguish between address
>>> and network.
>>
>> So use a different notation that is also supported by the library.
>
> I'm not referring to my software here -- I'm referring to applications
> like ifconfig that expect addresses to be formatted properly. If the
> default string representation produced by the ipaddr library does not
> match the canonical representation expected by software that has
> existed as long as IP itself, that indicates to me the library is
> doing something wrong.

I don't understand why you are trying to use ifconfig as an example.
It is actually a counter example to your thesis:  when working with an IP
address intended for consumption by ifconfig, you had best be using a
datatype that includes a netmask for that IP, or your code is going to
be broken.   What's more, modern versions of ifconfig _do_ accept the
default output format of ipaddr.  So this does the Right Thing:

     myip = ipaddr.IP('192.168.1.1/26')
     system('ifconfig eth0 {}'.format(myip))

If you use your ip-address-only class with ifconfig, you will wind up
using the classful default netmask, which is only going to be correct
by luck.

Hmm.  I think there is a conceptual divide here.  You have said you
think about IP addresses and networks as separate objects, so I wonder
if you would be pulling the netmask for ifconfig out of a separate
network object?

On the other hand I, a network professional, think about an IP address
paired with a netmask as a fundamental object.  Very rarely do I use
an IP address in isolation (without a netmask), and in many of _those_
cases there is an implied netmask of 255.255.255.255.  Networks to
me are closely related objects, defined by their "network number"
(the zero of the subnet, which is an IP address and normally not used
as a host address) and the mask.  So to me ipaddr's use of a single
datatype makes reasonable sense.  I would, as I said, above, find an
ip-without-netmask data type to be also useful (but a lot less important!)
I would also find a subclass that was network-only (rejects anything
but the zero of the subnet for the IP) useful.  But I think both of
those can be implemented fairly trivially as subclasses of the existing
ipaddr objects.

--David

PS: I've looked briefly at netaddr, and while I could probably work with
it by adding some equally trivial support code, I don't think it would
serve my needs as well as ipaddr will.  In particular, this is _very_
troubling:

>>> import netaddr
>>> ip = netaddr.IP('192.168.1.1/26')
>>> ip
IP('192.168.1.1/26')
>>> ip2 = netaddr.IP('192.168.1.1/27')
>>> ip2
IP('192.168.1.1/27')
>>> ip == ip2
True

The docs say the netmask is accepted only for "user convenience",
but to me the netmask is an integral part of the data entity I want to
manipulate.  Nor can I express ip-address-with-netmask using the CIDR
data type, since it will not accept anything but the zero of the network
as the IP.

In short, netaddr's object model does not match my desired model, while
ipaddr's is a lot closer to my desired model.


More information about the Python-Dev mailing list