classification
Title: Add Google's ipaddr.py to the stdlib
Type: Stage:
Components: Versions: Python 3.1
process
Status: closed Resolution: accepted
Dependencies: Superseder:
Assigned To: gregory.p.smith Nosy List: Rhamphoryncus, belopolsky, benjamin.peterson, claymation, ezio.melotti, giampaolo.rodola, gregory.p.smith, gvanrossum, loewis, mattsmart, oubiwann, pitrou, pmoody, pnasrat, r.david.murray, shields
Priority: normal Keywords:

Created on 2008-09-24 23:14 by gvanrossum, last changed 2009-06-02 17:00 by belopolsky. This issue is now closed.

Files
File name Uploaded Description Edit
unnamed mattsmart, 2009-05-02 00:50
Messages (81)
msg73761 - (view) Author: Guido van Rossum (gvanrossum) * (Python committer) Date: 2008-09-24 23:14
Google just released ipaddr.py, a module that knows how to manipulate IP
addresses (both IPv4 and IPv6).

I have nothing to do with this module, but I suggest considering it for
inclusion in the standard library.

It fills a gap for address manipulations that will become more important
to fill as IPv6 becomes more widespread.
msg73762 - (view) Author: Benjamin Peterson (benjamin.peterson) * (Python committer) Date: 2008-09-24 23:15
Where can we find this?
msg73763 - (view) Author: Guido van Rossum (gvanrossum) * (Python committer) Date: 2008-09-24 23:15
It would help if I added a link to the Google release:

http://code.google.com/p/ipaddr-py/

Description:

"

An IPv4/IPv6 manipulation library in Python.

This library is used to create/poke/manipulate IPv4 and IPv6 addresses
and prefixes.

"
msg73764 - (view) Author: Benjamin Peterson (benjamin.peterson) * (Python committer) Date: 2008-09-24 23:16
Almost time machine. :)
msg73768 - (view) Author: Martin v. Löwis (loewis) * (Python committer) Date: 2008-09-25 04:07
I see a list of owners in the code (although it's difficult to infer
real names or email addresses from that list). I think we should not
include the code without their explicit approval.

The question will then always be: what is the official master copy of
the code? The one in Python, or the one on Google code? Whose
responsibility would it be to keep those synchronized, and incorporate
changes from one copy into the other?

I would prefer if the copy in Python (say, 2.7) becomes the master copy,
and the copy on Google code eventually disappears (when interest in
older Python versions has died).

I would object to a mere fork of the code (i.e. where one of the regular
Python committers incorporates, from time to time, the changes that
Google made)
msg73770 - (view) Author: pmoody (pmoody) * (Python committer) Date: 2008-09-25 05:53
as one of the owners listed in the code.google.com project (same name),
and the original author, you certainly have my approval for inclusion in
python.
msg73793 - (view) Author: Guido van Rossum (gvanrossum) * (Python committer) Date: 2008-09-25 14:05
On Wed, Sep 24, 2008 at 9:07 PM, Martin v. Löwis <report@bugs.python.org> wrote:
> Martin v. Löwis <martin@v.loewis.de> added the comment:
> I see a list of owners in the code (although it's difficult to infer
> real names or email addresses from that list). I think we should not
> include the code without their explicit approval.

I know they *want* this to happen, no worries on this front.

> The question will then always be: what is the official master copy of
> the code? The one in Python, or the one on Google code? Whose
> responsibility would it be to keep those synchronized, and incorporate
> changes from one copy into the other?
>
> I would prefer if the copy in Python (say, 2.7) becomes the master copy,
> and the copy on Google code eventually disappears (when interest in
> older Python versions has died).

I'm in favor of this, and I believe the authors at Google are too --
it was written out of necessity, and once integrated, the need for a
separate Google copy will go away.

> I would object to a mere fork of the code (i.e. where one of the regular
> Python committers incorporates, from time to time, the changes that
> Google made)

Agreed.
msg74092 - (view) Author: STINNER Victor (haypo) * (Python committer) Date: 2008-09-30 18:25
I'm the maintainer of IPy library. Another library for IPv4/IPv6 
manipulation. The code is old (was written for Python 2.2?), but 
released under BSD license. Main issue of this library: it's unable to 
manipulation "invalid ranges": 10.20.4.0/30 is valid but 
10.20.4.1-10.20.4.5 is invalid since it's not possible to create a 
bitmask matching the range. I don't care if you choose Google library, 
maybe better. But you might check IPy to reuse some idea ;-)
msg74093 - (view) Author: STINNER Victor (haypo) * (Python committer) Date: 2008-09-30 18:25
Ooops, the website: http://software.inl.fr/trac/wiki/IPy
msg74094 - (view) Author: STINNER Victor (haypo) * (Python committer) Date: 2008-09-30 18:27
Another Python library: http://erlug.linux.it/~da/soft/iplib/
msg78216 - (view) Author: Benjamin Peterson (benjamin.peterson) * (Python committer) Date: 2008-12-22 22:53
Now that 2.6 and 3.0 are out of the way, how should we move forward?
Will a PEP be required?
msg78218 - (view) Author: Martin v. Löwis (loewis) * (Python committer) Date: 2008-12-22 23:58
> Now that 2.6 and 3.0 are out of the way, how should we move forward?

I think some committer needs to take charge and work with the authors
on merging the code. If pmoody wants commit access, that should be set
up, and he should add it himself in a commit-after-review manner (with
an actual patch, including documentation and tests).

If he doesn't want to do the integration, some committer needs to
volunteer - I personally won't (lack of time).

In any case, we would need a copyright form signed, unless Guido can
confirm that the code is covered by some agreement between Google and
the PSF.

> Will a PEP be required?

I doubt that; a quick announcement to python-dev might be sufficient
(in general, a PEP should only be done if dissent is likely). It
seems that Victor didn't actually disagree to integrating this
package; we should somehow encourage IPy users to review the code
and comment on the (possibly lack of) functionality.
msg78666 - (view) Author: David Moss (drkjam) Date: 2008-12-31 23:43
I think this might be worth a look before any hard and fast decisions
are made :-

http://code.google.com/p/netaddr/
msg78673 - (view) Author: pmoody (pmoody) * (Python committer) Date: 2009-01-01 01:08
I'm biased ;) but I don't see what netaddr provides over ipaddr.  it
also seems to be in the neighborhood of 50% slower (at least on my mac
mini).

pmoody@mini - 04:52 PM - ~/Downloads/ipaddr-1.0.1
-> python -m timeit 'import ipaddr;\
ipaddr.IP("1.1.1.1")'
10000 loops, best of 3: 46.2 usec per loop

pmoody@mini - 04:52 PM - ~/Downloads/netaddr-0.5.2
-> python -m timeit 'import netaddr;\
netaddr.IP("1.1.1.1")'
10000 loops, best of 3: 71.9 usec per loop

dealing with netmasks, the difference is even greater.
pmoody@mini - 04:52 PM - ~/Downloads/ipaddr-1.0.1
-> python -m timeit 'import ipaddr;\
ipaddr.IP("1.1.1.1/255.255.255.0")'
10000 loops, best of 3: 78.4 usec per loop

pmoody@mini - 04:49 PM - ~/Downloads/netaddr-0.5.2
-> python -m timeit 'import netaddr;\
> netaddr.IP("1.1.1.1/255.255.255.0")'
1000 loops, best of 3: 247 usec per loop

(and it doesn't seem to deal with hostsmasked addresses).

it also seems to be layed out in an unintuitive way, treating address
ranges a something very different than network addresses. hopefully
someone who isn't intimately familiar with both libraries can comment,
but ipaddr feels a lot cleaner to me.
msg78675 - (view) Author: Jean-Paul Calderone (exarkun) * (Python committer) Date: 2009-01-01 01:36
Performance shouldn't be a major concern here.  Utility is more
important and the implementation can be optimized later.

My initial impression of netaddr is pretty good.  One thing it has going
for it is documentation.  The netaddr google page gives a really great
overview of the functionality provided.  In comparison, the ipaddr-py
page is extremely sparse; the documentation in the repository is no
better (as there isn't really any).

There are a lot of minor things about ipaddr-py which are off-putting. 
It uses a naming convention that's not like any real Python software I'm
familiar with.  In particular, CamelCase method names really draw the
eye (in a bad way) and distract from the actual functionality being
provided.  I assume that if ipaddr-py is selected for inclusion, the API
will be adapted to fit PEP 8.  In comparison, netaddr appears to largely
comply with PEP 8 already.

Regarding the treatment of addresses versus address ranges, I prefer
netaddr's solution.  An address is not the same as an address range.  It
seems odd to try to represent them both with the same type as ipaddr-py
does.  This feels somewhat APLesque (where everything is a vector),
which isn't bad in itself, but generally if I want to manipulate an IP
address, I'm not thinking about it as a list of one address.  If I
wanted to do that, then I'd make a list and put the address in it.  By
comparison, the separate CIDR type in netaddr makes a lot of sense.  It
preserves a memory-efficient representation of the address range, but
does it with a different type than the fundamental address type.

This is far from a complete review of either library, obviously.  I've
done little more than glance over the documentation of each and do a
small amount of interactive playing around.  A lot more effort seems to
have gone into making netaddr accessible and appealing, and I think it
has succeeded.  Perhaps if some documentation for ipaddr-py is written
it will be easier to see where that library excels.  Of course, I assume
this is a prerequisite for inclusion in the standard library as well.
msg78677 - (view) Author: pmoody (pmoody) * (Python committer) Date: 2009-01-01 02:00
hm, all addresses have a subnet, even if its an implied /32, so
specifying a network as ("1.1.1.0", "1.1.1.255") seems a lot more
off-putting than "1.1.1.0/24". You're also much more likely to see the
latter in network devices. I guess I don't see the utility in an address
range of .1 - .22 (or something arbitrary, something which doesn't fall
on a power-of-2 boundary); when dealing with ranges of addresses, i've
always only wanted to/needed to manipulate sub-networks of addresses.

and my expectation was always that method names, etc. would have to be
converted to more closely match other python code; ipaddr was written to
google's python style guide, which I understand can be different than
the python.org style guide ;)

also, ipaddr does make extensive use of pydoc, but you're right, the
webpage is spartan.

happy (PST) new year.

Cheers,
/peter
msg78680 - (view) Author: Jean-Paul Calderone (exarkun) * (Python committer) Date: 2009-01-01 02:14
> hm, all addresses have a subnet, even if its an implied /32, so
specifying a network as ("1.1.1.0", "1.1.1.255") seems a lot more
off-putting than "1.1.1.0/24". You're also much more likely to see the
latter in network devices.

I'm not sure which API in netaddr you're referring to.  If you want to
construct that /24 with netaddr, then I would use
netaddr.address.CIDR("1.1.1.0/24").  Offhand, I can't find an API which
accepts two endpoints of a range to construct a network in netaddr. 
When I wrote about having separate types for individual addresses vs
ranges of addresses in my previous comment, I had IP and CIDR
respectively in mind, as opposed to ipaddr-py's single IPv4 class which
can represent either.
msg78683 - (view) Author: pmoody (pmoody) * (Python committer) Date: 2009-01-01 02:33
> I'm not sure which API in netaddr you're referring to.  If you want to
> construct that /24 with netaddr, then I would use
> netaddr.address.CIDR("1.1.1.0/24").  Offhand, I can't find an API which

netaddr.AddrRange

class AddrRange(__builtin__.object)
 |  A block of contiguous network addresses bounded by an arbitrary start and
 |  stop address. There is no requirement that they fall on strict bit mask
 |  boundaries, unlike L{CIDR} addresses.
 |

 |  __init__(self, first, last, klass=<class 'netaddr.address.Addr'>)
 |      Constructor.
 |
 |      @param first: start address for this network address range.
 |
 |      @param last: stop address for this network address range.
 |
 |      @param klass: (optional) class used to create each object returned.
 |          Default: L{Addr()} objects. See L{nrange()} documentations for
 |          additional details on options.

when looking through the code.google.com wiki, I couldn't find any
examples of creating addresses with netmasks and AddrRange was the
first thing I found when looking through pydoc.

> accepts two endpoints of a range to construct a network in netaddr.
> When I wrote about having separate types for individual addresses vs
> ranges of addresses in my previous comment, I had IP and CIDR
> respectively in mind, as opposed to ipaddr-py's single IPv4 class which
> can represent either.

and still having two separate classes represent the same thing seems odd to me.
msg78700 - (view) Author: David Moss (drkjam) Date: 2009-01-01 12:01
ipaddr appears to be on a fast track for "batteries included" status
without much consultation in the wider Python community. As BDFL it's
ultimately Guido's call, but it would be disappointing to see one
solution being chosen wholesale without much additional discussion.

There is no point in wrangling over the individual features of one
library at revision x versus another at revision y. Software is a moving
target. Omissions and bugs are easily dispatched. Ultimately we all want
the same thing, better software that makes our lives easier.

As for netaddr it is intended to cover more ground that all the other
solutions out there. Here is a handy list of them :-

http://code.google.com/p/netaddr/wiki/YetAnotherPythonIPModule

This may preclude its suitability for the standard library in any event
being intended to support any and all network address types, not just
IPv4 and IPv6. It is also currently, very much in beta, being about 75%
feature complete with 6-9 months work of (part-time) work left on it
before it can reach version 1.0 ready. A Python 3.0 version is also
planned for release soon.

In answer to various specific issues raised about netaddr.

The need for separate IP and CIDR classes is set out in the FAQ page :-

http://code.google.com/p/netaddr/wiki/NetAddrFAQ

FYI, AddrRange is a (not yet abstract) base class with a start and end
address covering the shared functionality of 3 subclasses (IPRange,
CIDR, Wildcard) which should all interchangeable (within reason). It is
also supports generic address (Addr objects) rather than just IP
specific ones. Base 2 slices is not always the best way of expressing
groups of network hosts, they are *one* way.

With netaddr, I wanted to avoid the 'super object' syndrome that seems
to dog virtuall all other existing efforts out there, and not only those
in Python.

In any event confusion will hopefully be dealt with as the docs improve.

As for performance, netaddr's current speed for certain operations areas
may be slower than other implementations but the optimisation phase of
development hasn't even begun. There are loads more features to add and
get working before that starts.

One point I will make is on licensing. netaddr is BSD, so you can do
whatever you want with it and contribute as you see fit.

At the present time, contributing to ipaddr for anyone outside Google
seems like the software equivalent of climbing Mount Everest! Even if I
personally wanted to contribute to this particular project's efforts,
having to sign the individual CLA would automatically preclude me from
doing so. This is a *major* sticking point.

Regardless of whatever decision is taken, netaddr will always be
available as long as it has a user base, either as built in, optional
extra or as a part of some wider standardisation effort.
msg78826 - (view) Author: Martin v. Löwis (loewis) * (Python committer) Date: 2009-01-02 16:07
> I think this might be worth a look before any hard and fast decisions
> are made :-
> 
> http://code.google.com/p/netaddr/

Looking at code isn't really helpful for determining whether it can
be included into Python. What matters more is whether the authors
want to contribute it, how they want to support it afterwards, and
so on.
msg78836 - (view) Author: Martin v. Löwis (loewis) * (Python committer) Date: 2009-01-02 16:38
> One point I will make is on licensing. netaddr is BSD, so you can do
> whatever you want with it and contribute as you see fit.

That is not sufficient for inclusion to Python. We also want support
from the author (along with a promise to eventually give up the external
project).
msg78908 - (view) Author: pmoody (pmoody) * (Python committer) Date: 2009-01-03 00:13
> That is not sufficient for inclusion to Python. We also want support
> from the author (along with a promise to eventually give up the external
> project).

As Guido had mentioned in a previous message, this is along the lines
of my thinking wrt ipaddr.

Cheers,
/peter
msg78984 - (view) Author: Duncan McGreggor (oubiwann) Date: 2009-01-03 18:03
I am a contributor to netaddr, having deprecated my own old and crufty 
IP address library in its favor. JP's comments on the library in this 
ticket are included in the set of reasons that I initially chose it to 
replace my own.

When I first looked at the ipaddr code a month ago, the features I was 
delighted to see in the ipaddr project include address exclusion and 
address collapsing (we'd been discussing these features in netaddr since 
my old project had similar functionality).

Perhaps the following might be a prudent course:
 * determine how small or big a standard library ip address module or 
subpackage should be;
 * have a mutual discussion on the netaddr and ipaddr mail lists to 
determine what would need to be changed in each project in order to 
support inclusion in the standard lib;
 * choose the option that requires the least code changes (simple naming 
convention changes should probably be given less weight than any changes 
to logic).

As for shutting down any project that is chosen, does such an action not 
leave older Python versions out in the cold? Shouldn't the project 
remain open to support Python versions < 2.7, with a highly visible note 
that the code is included in 2.7/3.1+? (I am completely ignorant of 
related Python development policy.)
msg78985 - (view) Author: Martin v. Löwis (loewis) * (Python committer) Date: 2009-01-03 18:12
> Perhaps the following might be a prudent course:

This sounds all good. It is better if the experts in a domain
make a recommendation, than if some random committer makes
a choice.

> As for shutting down any project that is chosen, does such an action not 
> leave older Python versions out in the cold? Shouldn't the project 
> remain open to support Python versions < 2.7, with a highly visible note 
> that the code is included in 2.7/3.1+? 

Of course - hence I said "eventually". The project could continue to
maintain the external version as long as they please, provided it
doesn't diverge from the in-core version (unless it is the in-core
version itself that diverges). What I don't want to see happen is that
the community recommends at some point to ignore the outdated crappy
version in the core, and replace it with the more-powerful bug-fixed
version available separately. This has happened in the past, so I'm
extremely cautious here.
msg78988 - (view) Author: Duncan McGreggor (oubiwann) Date: 2009-01-03 18:46
>> As for shutting down any project that is chosen, does such an action 
not 
>> leave older Python versions out in the cold? Shouldn't the project 
>> remain open to support Python versions < 2.7, with a highly visible 
note 
>> that the code is included in 2.7/3.1+? 
>
> Of course - hence I said "eventually". The project could continue to
> maintain the external version as long as they please, provided it
> doesn't diverge from the in-core version (unless it is the in-core
> version itself that diverges). What I don't want to see happen is that
> the community recommends at some point to ignore the outdated crappy
> version in the core, and replace it with the more-powerful bug-fixed
> version available separately. This has happened in the past, so I'm
> extremely cautious here.

Fantastic! Thanks for the clarification.

David, in the event of netaddr's complete or partial inclusion, are you 
+1 with this and the maintenance of an ip/net library in Python?

Guido, what is your preference regarding feature set/size for an ip/net 
library in Python?
msg78989 - (view) Author: Antoine Pitrou (pitrou) * (Python committer) Date: 2009-01-03 18:56
If there's going to be lots of discussion, perhaps it should be taken to
python-dev?
msg79069 - (view) Author: David Moss (drkjam) Date: 2009-01-04 16:27
> David, in the event of netaddr's complete or partial inclusion, 
> are you +1 with this and the maintenance of an ip/net library 
> in Python?

Yes, I would be very happy to help with this.

> If there's going to be lots of discussion, perhaps it should be 
> taken to python-dev?

Good idea.

Peter M. and the ipaddr contributors, are you all happy to proceed in
accordance with Duncan's suggestions? If so, let's kick off a thread on
python-dev to get the ball rolling and see what we can come up with.
msg79098 - (view) Author: pmoody (pmoody) * (Python committer) Date: 2009-01-05 00:16
> Good idea.
>
> Peter M. and the ipaddr contributors, are you all happy to proceed in
> accordance with Duncan's suggestions? If so, let's kick off a thread on
> python-dev to get the ball rolling and see what we can come up with.

I'm fine with this. But as Duncan mentioned, some guidance from the
benevolent powers that be on what exactly they're looking for before
we launch into a bunch of work would be appreciated.

Cheers,
/peter
msg79099 - (view) Author: Martin v. Löwis (loewis) * (Python committer) Date: 2009-01-05 00:36
> I'm fine with this. But as Duncan mentioned, some guidance from the
> benevolent powers that be on what exactly they're looking for before
> we launch into a bunch of work would be appreciated.

I think Guido's original message summarizes that: a module that
fills a gap for address manipulations... In addition, it should
have all the organisational qualities (happy user base, determined
maintainers, copyright forms, documentation, tests). As to what
precisely its API should be - that is for the experts (i.e. you)
to determine. I personally think performance is important, in
addition to a well-designed, useful API. Conformance to PEP 8
is also desirable.
msg79187 - (view) Author: Guido van Rossum (gvanrossum) * (Python committer) Date: 2009-01-05 19:21
I've been on vacation and unable to follow this, and won't have time to
catch up now. Note that I have no vested interest in Google's module
except knowing it has many happy users (I have never used it myself --
but Collin Winter has and he tells me it's great).

Since I haven't used either module and am not particularly interested in
this functionality, I'm withdrawing myself from the set of experts who
can decide which is better.

Duncan McGreggor asked some questions on python-dev; here are my responses:

>  * do we want to limit it to IP (i.e. no EUI/MAC support)?

I don't want to exclude EUI/MAC support, but it seems quit a separate
(and much more specialized) application area, so it's probably best to
keep it separate (even if it may make sense to use a common (abstract
or concrete) base class or just have similar APIs).

>  * do we want a single module or is a package acceptable?

I don't care either way.

>  * other thoughts?

How about a merger?
msg81006 - (view) Author: pmoody (pmoody) * (Python committer) Date: 2009-02-02 21:57
(kicking an old thread)

On Mon, Jan 5, 2009 at 11:21 AM, Guido van Rossum
<report@bugs.python.org> wrote:
>
> Guido van Rossum <guido@python.org> added the comment:
>
> I've been on vacation and unable to follow this, and won't have time to
> catch up now. Note that I have no vested interest in Google's module
> except knowing it has many happy users (I have never used it myself --
> but Collin Winter has and he tells me it's great).
>
> Since I haven't used either module and am not particularly interested in
> this functionality, I'm withdrawing myself from the set of experts who
> can decide which is better.
>
> Duncan McGreggor asked some questions on python-dev; here are my responses:
>
>>  * do we want to limit it to IP (i.e. no EUI/MAC support)?
>
> I don't want to exclude EUI/MAC support, but it seems quit a separate
> (and much more specialized) application area, so it's probably best to
> keep it separate (even if it may make sense to use a common (abstract
> or concrete) base class or just have similar APIs).
>
>>  * do we want a single module or is a package acceptable?
>
> I don't care either way.
>
>>  * other thoughts?
>
> How about a merger?

so we've talked about this on the ipaddr/netaddr lists and it seems
like a merger is pretty unlikely.  ipaddr and netaddr have some pretty
fundamental design differences, to the point where a merger wouldn't
mean a complete re-write of one or the other (in which case we're back
to picking one over the other).

so I guess a decision needs to be made. Is this something that should
be made on python-dev or does this bug have enough visibility?

for ipaddr's part, trunk is now pep8 compliant (with some backwards
compatible aliases).  I also know that David hasn't stopped adding
features to netaddr as well.

So, where do we go from here?

Cheers,
/peter

> _______________________________________
> Python tracker <report@bugs.python.org>
> <http://bugs.python.org/issue3959>
> _______________________________________
>
msg81007 - (view) Author: Guido van Rossum (gvanrossum) * (Python committer) Date: 2009-02-02 22:04
Beats me. I personally haven't had the pleasure to use either so I can't
decide.  Maybe a vote or a bake-off?
msg81009 - (view) Author: Duncan McGreggor (oubiwann) Date: 2009-02-02 22:14
Well, here are my thoughts on the matter:
 * ipaddr is relatively small, fast, and focuses on some core functionality
 * netaddr is designed to be very flexible (sometimes at the cost of a
little speed), leaning more towards a network calculation/address
manipulation "framework"

As such, and given the recent work made to ipaddr to make it
stdlib-friendly, my vote would be to include ipaddr in Python while
netaddr can continue growing, providing its user base with diverse
functionality while hopefully taking advantage of ipaddr in the Python
stdlib as much as is practical and useful.
msg81010 - (view) Author: Martin v. Löwis (loewis) * (Python committer) Date: 2009-02-02 22:19
> so I guess a decision needs to be made. Is this something that should
> be made on python-dev or does this bug have enough visibility?

The bug doesn't have enough visibility, so it definitely needs to be
discussed in public.

> So, where do we go from here?

Maybe some committer is willing to make a decision (I know that I will
not, but I wouldn't be opposed to somebody else making one).

Lacking that, the ususal procedures apply: either
a) publish the respective code on the relevant sites, build community,
   and come back in a few years, or
b) write a PEP, and ask for BDFL pronouncement in the end.

IOW, it is not clear to me why a decision *needs* to be made (unless
you count "defer" as a decision as well). Of course, in either a and
b, there is a chance that the result will again be "defer"
msg81011 - (view) Author: Martin v. Löwis (loewis) * (Python committer) Date: 2009-02-02 22:26
> As such, and given the recent work made to ipaddr to make it
> stdlib-friendly, my vote would be to include ipaddr in Python while
> netaddr can continue growing, providing its user base with diverse
> functionality while hopefully taking advantage of ipaddr in the Python
> stdlib as much as is practical and useful.

I could live with such a choice if the netaddr authors agree that it
is the right choice (them being experts themselves in the domain).
I don't want to be accused of drkjam's accusation of fast-tracking
code just because it comes from Google (which would be a false
accusation regardless, but there is no reason to make some Python
users unhappy because they feel they are subject to political games).
msg81050 - (view) Author: David Moss (drkjam) Date: 2009-02-03 13:11
For reference, here are the (cross-posted) links to the discussion on 
the (now failed) netaddr/ipaddr merge talks :-

http://groups.google.com/group/netaddr/browse_thread/thread/f80b7c69e459
02b7
http://groups.google.com/group/ipaddr-py-
dev/browse_thread/thread/2bc329151fef01eb

Out of interest, here is some data from each project's download 
counters (taken 2nd Feb 2009) :-

project: netaddr
total downloads: 3298
first official release: July 7th, 2008

project: ipaddr 
total downloads: 998
first official release: September 24th, 2008

This only includes those accessing official releases (not direct 
subversion repository access). As these projects are both still less 
the 6 months old its probably difficult to gauge any kind of long term 
trend from this. However, what it does show is the high level of user 
interest in both projects.

I have no desire to continue being a blocker on the decision to include 
ipaddr in the stdlib. At this point, I'm sure we are all keen to move 
on.

As previously stated, netaddr will continue to be a viable alternative 
to those users that prefer its interface, documentation, additional 
features (layer-2 options, etc) and direction.

Choice is a good thing and that choice will remain open to Python users 
as long as their interest persists.
msg81141 - (view) Author: pmoody (pmoody) * (Python committer) Date: 2009-02-04 16:25
> I could live with such a choice if the netaddr authors agree that it
> is the right choice (them being experts themselves in the domain).
> I don't want to be accused of drkjam's accusation of fast-tracking
> code just because it comes from Google (which would be a false
> accusation regardless, but there is no reason to make some Python
> users unhappy because they feel they are subject to political games).

in light of david's email, would you agree that the bar for buy-in has
been met or should I now start writing a PEP and preparing offerings
for the BDFL?

Cheers,
/peter
msg81144 - (view) Author: Guido van Rossum (gvanrossum) * (Python committer) Date: 2009-02-04 17:07
I don't think a PEP is needed, and I do think ipaddr.py is ready for
inclusion.  All that you really need is a core developer to champion the
inclusion.
msg81146 - (view) Author: Antoine Pitrou (pitrou) * (Python committer) Date: 2009-02-04 18:02
Probably it has already been said, but for the record: is ipaddr's
current API ok for other libraries (mainly: netaddr) to build upon it
and provide compatible extensions or replacements, or would netaddr
become an incompatible alternative to the stdlib-provided ipaddr? The
latter would be a shame.
msg81147 - (view) Author: Duncan McGreggor (oubiwann) Date: 2009-02-04 18:22
Antione,

We're (netaddr) going to try to use ipaddr if possible, but there are 
operations which we are providing to API users that aren't directly
supported by ipaddr. We haven't yet determined the level of effort
involved in trying to work with ipaddr's base classes in supporting
these, but it may be more effort (and code) than it's worth (the
benefits of using ipaddr may be lost).

In a sense, it would be a shame. But on the other hand, we have examples
where 3-rd party web frameworks don't use the built-in HTTP server, and
that hasn't been a problem. In many ways, netaddr is evolving into an IP
manipulation framework. Those that need its features can use it; those
that just need the basics will be able to get that in the stdlib.

In any case, it will be in our best interest to provide some
compatibility layer between the two :-)
msg81150 - (view) Author: Guido van Rossum (gvanrossum) * (Python committer) Date: 2009-02-04 18:45
If changes to ipaddr could make things easier for netaddr's support of
advanced features, please do propose those changes!
msg81151 - (view) Author: Martin v. Löwis (loewis) * (Python committer) Date: 2009-02-04 19:27
> in light of david's email, would you agree that the bar for buy-in has
> been met or should I now start writing a PEP and preparing offerings
> for the BDFL?

Yes, I think it can be integrated now. I'll look into it, unless
somebody is faster (it could well take some weeks until I find some
time)
msg81167 - (view) Author: Duncan McGreggor (oubiwann) Date: 2009-02-04 21:53
> If changes to ipaddr could make things easier for netaddr's support
> of advanced features, please do propose those changes!

Thanks, Guido -- we will :-) We'll be watching closely for that and
participating as much as possible.
msg82684 - (view) Author: pmoody (pmoody) * (Python committer) Date: 2009-02-24 23:06
Are there any committers who'd be able to help get this integrated?
Martin is booked solid until April and that would apparently
jeopardize the inclusion of ipaddr in python 3.1.

Cheers,
/peter

On Wed, Feb 4, 2009 at 11:27 AM, Martin v. Löwis <report@bugs.python.org> wrote:
>
> Martin v. Löwis <martin@v.loewis.de> added the comment:
>
>> in light of david's email, would you agree that the bar for buy-in has
>> been met or should I now start writing a PEP and preparing offerings
>> for the BDFL?
>
> Yes, I think it can be integrated now. I'll look into it, unless
> somebody is faster (it could well take some weeks until I find some
> time)
>
> _______________________________________
> Python tracker <report@bugs.python.org>
> <http://bugs.python.org/issue3959>
> _______________________________________
>
msg82688 - (view) Author: Antoine Pitrou (pitrou) * (Python committer) Date: 2009-02-25 01:44
You should post a message on python-dev and put your patch on Rietveld,
this will give you more chances to find an interested developer.
msg82695 - (view) Author: Gregory P. Smith (gregory.p.smith) * (Python committer) Date: 2009-02-25 05:21
I'll take care of this.  My goal is to do it before PyCon.
msg84445 - (view) Author: Gregory P. Smith (gregory.p.smith) * (Python committer) Date: 2009-03-29 23:45
benjamin.peterson mentioned this in his whats new in 3.1 lightning talk
at pycon today and completely by chance, I had made showing a couple
examples of ipaddr the topic of my own lightning talk ~30 minutes later. :)

Anyways I hope to commit this for 3.1 and 2.7 during the python-dev
sprints this week after we get some sphinx .rst style documentation
written up (I'll base it off the wiki).
msg86898 - (view) Author: Gregory P. Smith (gregory.p.smith) * (Python committer) Date: 2009-05-01 20:00
Committed to trunk (2.7) in r72173.  I'll merge it into py3k later this
afternoon.
msg86902 - (view) Author: Antoine Pitrou (pitrou) * (Python committer) Date: 2009-05-01 20:16
Is there any chance the test methods in test_ipaddr can be PEP8-ified?
msg86903 - (view) Author: pmoody (pmoody) * (Python committer) Date: 2009-05-01 20:19
I'll submit a change for this to trunk in a second.

On Fri, May 1, 2009 at 1:16 PM, Antoine Pitrou <report@bugs.python.org> wrote:
>
> Antoine Pitrou <pitrou@free.fr> added the comment:
>
> Is there any chance the test methods in test_ipaddr can be PEP8-ified?
>
> ----------
>
> _______________________________________
> Python tracker <report@bugs.python.org>
> <http://bugs.python.org/issue3959>
> _______________________________________
>
msg86925 - (view) Author: pmoody (pmoody) * (Python committer) Date: 2009-05-01 23:49
well, sent it for review anyway.  is this a showstopper for submission?

On Fri, May 1, 2009 at 1:19 PM, pmoody <report@bugs.python.org> wrote:
>
> pmoody <python@hda3.com> added the comment:
>
> I'll submit a change for this to trunk in a second.
>
> On Fri, May 1, 2009 at 1:16 PM, Antoine Pitrou <report@bugs.python.org> wrote:
>>
>> Antoine Pitrou <pitrou@free.fr> added the comment:
>>
>> Is there any chance the test methods in test_ipaddr can be PEP8-ified?
>>
>> ----------
>>
>> _______________________________________
>> Python tracker <report@bugs.python.org>
>> <http://bugs.python.org/issue3959>
>> _______________________________________
>>
>
> ----------
>
> _______________________________________
> Python tracker <report@bugs.python.org>
> <http://bugs.python.org/issue3959>
> _______________________________________
>
msg86926 - (view) Author: Antoine Pitrou (pitrou) * (Python committer) Date: 2009-05-01 23:50
Not at all, it's just nicer.
msg86928 - (view) Author: Gregory P. Smith (gregory.p.smith) * (Python committer) Date: 2009-05-02 00:48
I merged ipaddr into py3k.

I can't lookup the revision number (r72186?) at the moment since 
svn.python.org is having problems.

anyways, thanks pmoody & other ipaddr developers!

Now that the library is -in- (before the 3.1 beta cutoff :), non-API 
changing bug fixes and tweaks like that one are fine to apply to the 
python svn repo as appropriate.

I'm leaving this open pending merging the test pep8 change in once it is 
ready and svn.python.org is back online.
msg87033 - (view) Author: Gregory P. Smith (gregory.p.smith) * (Python committer) Date: 2009-05-03 07:04
r72210 pep8-ified the test names.
msg88653 - (view) Author: Clay McClure (claymation) Date: 2009-06-01 16:39
Since Python 2.7 and 3.1 have not yet shipped, I hope it's not too late 
to
continue this discussion. I have no vested interest in either ipaddr or
netaddr, but I am interested in seeing a well-designed and usable IP 
address
library included in the stdlib.

From reading the comments in this issue, it seems most of the discussion
focused on netaddr's API. There seems to have been little discussion 
about
the merits of ipaddr's API, which is unfortunate given that ipaddr is 
the
library being included in the stdlib. There was some technical 
discussion on
the ipaddr and netaddr lists, but it amounted to each developer 
defending his
library, and neither party seemed willing to compromise on key design
decisions. At the end of the reconciliation period, ipaddr looks much 
the
same as it did before, albeit with prettier indentation.

When looking for an IP address library for use in a network scanning and
discovery application I wrote last year, I decided against ipaddr 
because of
its conflation of address and network -- it seems strange to me to have 
one
class modeling both concepts.

After reading the technical discussion on the ipaddr and netaddr lists, 
it is
clear to me that ipaddr's designers have a somewhat limited 
understanding of
IP addressing, and have not designed an API that articulates IP concepts
particularly well. For example, see pmoody's earlier comments in this 
ticket:

> all addresses have a subnet, even if its an implied /32

This is not only incorrect, but it demonstrates a deep misunderstanding 
of
how IP works. IP addresses most certainly do not have a "subnet", or a 
mask
of any sort. An IPv4 address is simply a 32-bit number.

IPv4 *networks* have masks, of course, hence the name "netmask". These
network masks are used by the routing process to lookup the next hop (or
directly connected network) for an IP datagram by matching the 
datagram's
destination address against the networks and masks defined in the 
routing
table.

> specifying a network as ("1.1.1.0", "1.1.1.255") seems a lot more
> off-putting than "1.1.1.0/24".

Since networks are commonly represented in at least three forms, the API
should support at least these:

CIDR/prefix notation: "192.168.1.0/24"
address+mask notation: "192.168.1.0/255.255.255.0"
range notation: "192.168.1.0-192.168.1.255"

> I guess I don't see the utility in an address range of .1 - .22 
> (or something arbitrary, something which doesn't fall on a power-of-2
> boundary); when dealing with ranges of addresses, i've always only 
> wanted to/needed to manipulate sub-networks of addresses.

This statement demonstrates an extremely narrow view of the problem 
domain.
Access lists and DHCP pools are two common examples of where arbitrary
address ranges are useful.

At least three concepts deserve first-class treatment in any meaningful 
IP
address library:

* addresses
* ranges of addresses
* networks

To conflate these is a mistake.

My hope is that now that a library has been selected, it can be improved 
before Python 2.7 and 3.1 ship. Now is the best time to make
backwards-incompatible API changes; once ipaddr ships with the stdlib, 
we're
stuck with it. If it remains as-is, it will be deadweight for those app
developers like myself who prefer an API that more accurately reflects 
the
problem domain.

To this end, now that ipaddr is moving to Python stdlib, will Google's
contributor license agreement restriction be lifted? I would like to
contribute, but have not been able to secure a corporate CLA from my
employer.

Cheers,

Clay
msg88654 - (view) Author: Gregory P. Smith (gregory.p.smith) * (Python committer) Date: 2009-06-01 17:00
On Mon, Jun 1, 2009 at 9:39 AM, Clay McClure <report@bugs.python.org> wrote:
>
> Since Python 2.7 and 3.1 have not yet shipped, I hope it's not too late
> to continue this discussion. I have no vested interest in either ipaddr or
> netaddr, but I am interested in seeing a well-designed and usable IP
> address library included in the stdlib.

Python 3.1 is as good as shipped.  It is in the release candidate
stage which means no code changes other than bug fixes can go in.

Improvements will have to wait for 2.7 and 3.2.  In the mean time I
suggest writing up improvements as either subclasses of the existing
ipaddr module (so that they can be used both with this standalone
project and with the version shipped in python 3.1).

>> specifying a network as ("1.1.1.0", "1.1.1.255") seems a lot more
>> off-putting than "1.1.1.0/24".
>
> Since networks are commonly represented in at least three forms, the API
> should support at least these:
>
> CIDR/prefix notation: "192.168.1.0/24"
> address+mask notation: "192.168.1.0/255.255.255.0"
> range notation: "192.168.1.0-192.168.1.255"

I think range notation parsing could be implemented pretty easily.

> Access lists and DHCP pools are two common examples of where arbitrary
> address ranges are useful.
>
> At least three concepts deserve first-class treatment in any meaningful
> IP address library:
>
> * addresses
> * ranges of addresses
> * networks
>
> To conflate these is a mistake.
>
> My hope is that now that a library has been selected, it can be improved
> before Python 2.7 and 3.1 ship. Now is the best time to make
> backwards-incompatible API changes; once ipaddr ships with the stdlib,
> we're stuck with it. If it remains as-is, it will be deadweight for those app
> developers like myself who prefer an API that more accurately reflects
> the problem domain.

Too late for 3.1.  But I see no reason for the existing API to be
considered bad.  There is always room for improvement.  I believe you
could add support for network address ranges on top of it without too
much difficulty.

Subclass the existing classes and inherit from a mixin that keeps
track of a start and end of range and extends the 'in' operator to
check if the comparison address is >= and <= the start and end
addresses.

> To this end, now that ipaddr is moving to Python stdlib, will Google's
> contributor license agreement restriction be lifted? I would like to
> contribute, but have not been able to secure a corporate CLA from my
> employer.

You can sign a Python Software Foundation contributor agreement
instead.  http://www.python.org/psf/contrib/contrib-form/  We've been
a bit relaxed on requiring these from people at times but it is a good
thing to do for Python's sake.

No Google CLA will ever be required to make changes to anything in the
python project itself.
msg88655 - (view) Author: Martin v. Löwis (loewis) * (Python committer) Date: 2009-06-01 17:09
> My hope is that now that a library has been selected, it can be improved 
> before Python 2.7 and 3.1 ship.

That is fairly unlikely. The 3.1 release candidate has been produced,
so the only options possible at this point are to either go ahead with
what is in the code, or withdraw the library from 3.1 if it can be
demonstrated to have severe flaws.
msg88672 - (view) Author: Clay McClure (claymation) Date: 2009-06-01 20:33
On Mon, Jun 1, 2009 at 1:09 PM, Martin v. Löwis <report@bugs.python.org> wrote:

>> My hope is that now that a library has been selected, it can be improved
>> before Python 2.7 and 3.1 ship.
>
> That is fairly unlikely. The 3.1 release candidate has been produced,
> so the only options possible at this point are to either go ahead with
> what is in the code, or withdraw the library from 3.1 if it can be
> demonstrated to have severe flaws.

False
>>> ipaddr.IPv4('192.168.1.1') == ipaddr.IPv4('192.168.1.1/32')
True

ipaddr makes no distinction between two fundamentally different
concepts -- to my mind, that is a serious flaw.

ipaddr has many other quirks that, while not technically flaws, are
design warts that deserve to be fixed before its target audience is
amplified by its inclusion in the stdlib.

To those arguing for ipaddr's inclusion in the stdlib, how many of you
will actually use ipaddr to develop software? As an actual developer
of network scanning and discovery software, I can tell you that I
would rather roll my own library than use ipaddr as it exists today.

Clay
msg88673 - (view) Author: Clay McClure (claymation) Date: 2009-06-01 20:41
Strangely, the leading line of my last response was eaten by the bug 
tracker. It read:

>>> 1 == (1,)
msg88675 - (view) Author: pmoody (pmoody) * (Python committer) Date: 2009-06-01 20:51
On Mon, Jun 1, 2009 at 1:33 PM, Clay McClure <report@bugs.python.org> wrote:
>
> Clay McClure <clay@daemons.net> added the comment:
>
> On Mon, Jun 1, 2009 at 1:09 PM, Martin v. Löwis <report@bugs.python.org> wrote:
>
>>> My hope is that now that a library has been selected, it can be improved
>>> before Python 2.7 and 3.1 ship.
>>
>> That is fairly unlikely. The 3.1 release candidate has been produced,
>> so the only options possible at this point are to either go ahead with
>> what is in the code, or withdraw the library from 3.1 if it can be
>> demonstrated to have severe flaws.
>
> False
>>>> ipaddr.IPv4('192.168.1.1') == ipaddr.IPv4('192.168.1.1/32')
> True
>
> ipaddr makes no distinction between two fundamentally different
> concepts -- to my mind, that is a serious flaw.

I don't see these a fundamentally different, I guess.  can you
demonstrate how this equivalency makes ipaddr unusable?

> ipaddr has many other quirks that, while not technically flaws, are
> design warts that deserve to be fixed before its target audience is
> amplified by its inclusion in the stdlib.

I haven't seen any new issues on code.google.com (and I haven't heard
of any being reported on the python bugtracker), so since you're using
this thread to report issues, can you elaborate?

> To those arguing for ipaddr's inclusion in the stdlib, how many of you
> will actually use ipaddr to develop software? As an actual developer
> of network scanning and discovery software, I can tell you that I
> would rather roll my own library than use ipaddr as it exists today.

have used it to develop software and will continue to use it to
develop software.

Cheers,
/peter

> Clay
>
> ----------
>
> _______________________________________
> Python tracker <report@bugs.python.org>
> <http://bugs.python.org/issue3959>
> _______________________________________
>
msg88676 - (view) Author: Martin v. Löwis (loewis) * (Python committer) Date: 2009-06-01 20:54
> ipaddr makes no distinction between two fundamentally different
> concepts -- to my mind, that is a serious flaw.

Do you have an application in mind where this lack of distinction
would prevent writing the application in a straight-forward way?
IOW, could you do something if they were distinct that you can't
do because they are not?
msg88678 - (view) Author: R. David Murray (r.david.murray) * (Python committer) Date: 2009-06-01 21:02
> >>> ipaddr.IPv4('192.168.1.1') == ipaddr.IPv4('192.168.1.1/32')
> True

As a network engineer I don't see any inherent problem with that equality.
In fact I make use of that conceptual equality on a regular basis.

Further, if you were to add a specifically 'address-without-netmask'
type, the above equality would still be true, because then the above
would be comparing two addresses-with-netmasks and you would want to
apply the hostmask to a bare address for convenience.  To get inequality,
you'd be comparing two different object types...which comparison would
be False by default.
msg88686 - (view) Author: Clay McClure (claymation) Date: 2009-06-01 23:41
On Mon, Jun 1, 2009 at 5:02 PM, R. David Murray <report@bugs.python.org> wrote:

>> >>> ipaddr.IPv4('192.168.1.1') == ipaddr.IPv4('192.168.1.1/32')
>> True
>
> As a network engineer I don't see any inherent problem with that equality.
> In fact I make use of that conceptual equality on a regular basis.

For an example of why 192.168.1.1 != 192.168.1.1/32, look no further
than ifconfig:

# ifconfig en0 192.168.1.1/32
# ifconfig en0
en0: flags=8863<UP,BROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST> mtu 1500
	inet 192.168.1.1 netmask 0xffffffff broadcast 192.168.1.1
        ...

# ifconfig en0 192.168.1.1
# ifconfig en0
en0: flags=8863<UP,BROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST> mtu 1500
	inet 192.168.1.1 netmask 0xffffff00 broadcast 192.168.1.255
        ...

Can you provide an example of when 192.168.1.1 does in fact equal
192.168.1.1/32?

> Further, if you were to add a specifically 'address-without-netmask'
> type, the above equality would still be true, because then the above
> would be comparing two addresses-with-netmasks and you would want to
> apply the hostmask to a bare address for convenience.  To get inequality,
> you'd be comparing two different object types...which comparison would
> be False by default.

I don't follow. Assuming hypothetical Address and Network classes, as
accurately models the problem domain, we would have:

False

That seems to me the correct behavior, since an address is in fact not
the same thing as a network.

Clay
msg88688 - (view) Author: pmoody (pmoody) * (Python committer) Date: 2009-06-01 23:51
On Mon, Jun 1, 2009 at 4:41 PM, Clay McClure <report@bugs.python.org> wrote:
>
> Clay McClure <clay@daemons.net> added the comment:
>
> On Mon, Jun 1, 2009 at 5:02 PM, R. David Murray <report@bugs.python.org> wrote:
>
>>> >>> ipaddr.IPv4('192.168.1.1') == ipaddr.IPv4('192.168.1.1/32')
>>> True
>>
>> As a network engineer I don't see any inherent problem with that equality.
>> In fact I make use of that conceptual equality on a regular basis.
>
> For an example of why 192.168.1.1 != 192.168.1.1/32, look no further
> than ifconfig:
>
> # ifconfig en0 192.168.1.1/32
> # ifconfig en0
> en0: flags=8863<UP,BROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST> mtu 1500
>        inet 192.168.1.1 netmask 0xffffffff broadcast 192.168.1.1
>        ...
>
> # ifconfig en0 192.168.1.1
> # ifconfig en0
> en0: flags=8863<UP,BROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST> mtu 1500
>        inet 192.168.1.1 netmask 0xffffff00 broadcast 192.168.1.255
>        ...
>
> Can you provide an example of when 192.168.1.1 does in fact equal
> 192.168.1.1/32?

what this shows is that your copy of darwin defaults to a /24
prefixlen; ipaddr assumes a /32 prefixlen.  I don't see anything
particularly *more* intuitive with darwin, but in any event, it seems
to provide support for assuming a prefixlen when none is supplied.

>
> _______________________________________
> Python tracker <report@bugs.python.org>
> <http://bugs.python.org/issue3959>
> _______________________________________
>
msg88692 - (view) Author: R. David Murray (r.david.murray) * (Python committer) Date: 2009-06-02 00:05
In pre-CIDR days, assuming a prefixlen of 24 for a 192.168.x.x address
made sense.  Nowadays it is better not to make that assumption.  So I
find ipaddr's default of 32 to be "safer" than using a class based default.

The larger point, however, is that there _is_ a mask associated with the
address in ifconfig.  There _must_ be one.  So that is not an example
that shows that a separate address class is useful.

As for the == thing, I agreed with you that address compared to network,
if you had an address class, would yield false.  My point was that

    HypotheticalNetworkClass('192.168.1.1') ==
HypotheticalNetworkClass('192.168.1.1/32')

should yield True, because, as I said above, in a CIDR world using a
default of a hostmask for an otherwise unadorned address makes the most
sense.

As for an example of when the equivalence is useful, it is useful every
time I set up an access rule or route that applies to a single host. 
Otherwise, I _must_ give a specific netmask, because in real life the
classfull default is often not the correct netmask.  Most networking
software that I've dealt with requires explicit netmasks (often with a
shorthand to specify an ip/hostmask pair).  It is true that when a
netmask isn't required it generally defaults to the classful netmask,
but having such a default is becoming more rare with time, in my
experience (because of CIDR).
msg88700 - (view) Author: Clay McClure (claymation) Date: 2009-06-02 00:47
On Mon, Jun 1, 2009 at 4:54 PM, Martin v. Löwis <report@bugs.python.org> wrote:

> Do you have an application in mind where this lack of distinction
> would prevent writing the application in a straight-forward way?
> IOW, could you do something if they were distinct that you can't
> do because they are not?

Consider applications that use ipaddr.IPv4 objects to configure
network interfaces:

ifconfig: 255.255.255.0/32: bad value

That's because ipaddr wrongly appends a prefix length to all
ipaddr.IPv4 objects, even those representing addresses, which do not
have prefix lengths.

Consider applications that need to validate addresses (or networks,
but not both) supplied as user input:

address = ipaddr.IP(input)

if isinstance(address, ipaddr.IPv4):
    if address.prefixlen != 32:
        raise TypeError("Expecting IP address, not network")
elif isinstance(address, ipaddr.IPv6):
    if address.prefixlen != 128:
        raise TypeError("Expecting IP address, not network")

Given its myriad quirks, it is really rather surprising that ipaddr is
being considered for inclusion in the Python stdlib.

Clay
msg88703 - (view) Author: pmoody (pmoody) * (Python committer) Date: 2009-06-02 01:03
On Mon, Jun 1, 2009 at 5:47 PM, Clay McClure <report@bugs.python.org> wrote:
>
> Clay McClure <clay@daemons.net> added the comment:
>
> On Mon, Jun 1, 2009 at 4:54 PM, Martin v. Löwis <report@bugs.python.org> wrote:
>
>> Do you have an application in mind where this lack of distinction
>> would prevent writing the application in a straight-forward way?
>> IOW, could you do something if they were distinct that you can't
>> do because they are not?
>
> Consider applications that use ipaddr.IPv4 objects to configure
> network interfaces:
>
> ifconfig: 255.255.255.0/32: bad value
>
> That's because ipaddr wrongly appends a prefix length to all
> ipaddr.IPv4 objects, even those representing addresses, which do not
> have prefix lengths.

I'm not sure what you're trying to do here, can you elaborate?

> Consider applications that need to validate addresses (or networks,
> but not both) supplied as user input:
>
> address = ipaddr.IP(input)
>
> if isinstance(address, ipaddr.IPv4):
>    if address.prefixlen != 32:
>        raise TypeError("Expecting IP address, not network")
> elif isinstance(address, ipaddr.IPv6):
>    if address.prefixlen != 128:
>        raise TypeError("Expecting IP address, not network")

i'm not sure what's onerous about this code.  you're missing a
try/except around ipaddr.IP(), but otherwise it seems fine.

> Given its myriad quirks, it is really rather surprising that ipaddr is
> being considered for inclusion in the Python stdlib.

it's actually already been included, but that's beside the point.  I'm
now asking you a second time to submit bug reports if there are issues
which you see; perhaps these 'myriad of quirks' can be fixed, perhaps
not.  yelling here doesn't actually do anything productive.

> Clay
>
> ----------
>
> _______________________________________
> Python tracker <report@bugs.python.org>
> <http://bugs.python.org/issue3959>
> _______________________________________
>
msg88705 - (view) Author: Clay McClure (claymation) Date: 2009-06-02 01:27
On Mon, Jun 1, 2009 at 4:51 PM, pmoody <report@bugs.python.org> wrote:

>>>>> ipaddr.IPv4('192.168.1.1') == ipaddr.IPv4('192.168.1.1/32')
>> True
>>
>> ipaddr makes no distinction between two fundamentally different
>> concepts -- to my mind, that is a serious flaw.
>
> I don't see these a fundamentally different, I guess.  can you
> demonstrate how this equivalency makes ipaddr unusable?

Fortunately, it's not up for debate: RFC-791 defines an IP address as
a 32-bit number, with no provision for a mask. Networks are defined by
their address and their mask. To correctly model them in an
object-oriented system, we would say that a Network has-a Address,
certainly not that a Network is-a Address.

> I haven't seen any new issues on code.google.com (and I haven't heard
> of any being reported on the python bugtracker), so since you're using
> this thread to report issues, can you elaborate?

I will go ahead and open issues on code.google.com.

> have used it to develop software and will continue to use it to
> develop software.

I'd like to hear from application developers outside of Google. The
two that have commented on this issue seem not to prefer ipaddr's API.

Clay
msg88706 - (view) Author: Clay McClure (claymation) Date: 2009-06-02 02:03
On Mon, Jun 1, 2009 at 7:51 PM, pmoody <report@bugs.python.org> wrote:

>> For an example of why 192.168.1.1 != 192.168.1.1/32, look no further
>> than ifconfig:
>>
>> # ifconfig en0 192.168.1.1/32
>> # ifconfig en0
>> en0: flags=8863<UP,BROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST> mtu 1500
>>        inet 192.168.1.1 netmask 0xffffffff broadcast 192.168.1.1
>>        ...
>>
>> # ifconfig en0 192.168.1.1
>> # ifconfig en0
>> en0: flags=8863<UP,BROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST> mtu 1500
>>        inet 192.168.1.1 netmask 0xffffff00 broadcast 192.168.1.255
>>        ...
>
> what this shows is that your copy of darwin defaults to a /24
> prefixlen; ipaddr assumes a /32 prefixlen.  I don't see anything
> particularly *more* intuitive with darwin, but in any event, it seems
> to provide support for assuming a prefixlen when none is supplied.

The example demonstrates one case where the strings '192.168.1.1' and
'192.168.1.1/32' are not equivalent -- it wouldn't be hard to find
other examples -- yet you seem to think that (a) this is
Darwin-specific behavior, and that (b) this discrepancy is acceptable
and does not constitute a design flaw.

You're wrong on both fronts, since in fact all IP implementations
understand classful addressing (as per RFC-791), not just Darwin, and
your insistence on the equality of '192.168.1.1' and '192.168.1.1/32'
means that your library is unusable in applications that pass
ipaddr.IPv4 objects to ifconfig.

Clay
msg88707 - (view) Author: Clay McClure (claymation) Date: 2009-06-02 02:15
On Mon, Jun 1, 2009 at 8:05 PM, R. David Murray <report@bugs.python.org> wrote:

> In pre-CIDR days, assuming a prefixlen of 24 for a 192.168.x.x address
> made sense.  Nowadays it is better not to make that assumption.  So I
> find ipaddr's default of 32 to be "safer" than using a class based default.

Sorry, but why should you determine what is better for my application?

> The larger point, however, is that there _is_ a mask associated with the
> address in ifconfig.  There _must_ be one.  So that is not an example
> that shows that a separate address class is useful.

Again, you're wrong. The mask that you see in ifconfig is associated
with the network to which the interface is attached, not the interface
address. You also see a broadcast address in the ifconfig output, but
certainly you don't believe that the broadcast address is a property
of the interface address? No, of course not; it's a property of the
network to which the interface is attached -- just like the mask.

That's why we call it a "netmask".

> As for an example of when the equivalence is useful, it is useful every
> time I set up an access rule or route that applies to a single host.

Host routes are routes like all others -- they have a destination
address and a mask. That a host route has a prefix length of 32 does
not imply that the host route is equivalent to the host address.
You're confusing the two concepts.

> Most networking
> software that I've dealt with requires explicit netmasks (often with a
> shorthand to specify an ip/hostmask pair).

By "ip/hostmask" pair, you actually mean "ip/netmask" pair, and yes,
this is a convenient notation for expressing two distinct but related
concepts: an address, and a mask. Addresses do not have masks;
networks do. I am not sure how to be any more clear about that point,
yet you still seem not to understand.

> It is true that when a
> netmask isn't required it generally defaults to the classful netmask,
> but having such a default is becoming more rare with time, in my
> experience (because of CIDR).

I'm not advocating classful routing, I'm merely stating (emphatically
and without ambiguity) that addresses and networks are different:
networks have masks; addresses do not. The ipaddr library forces a
mask on me every time I specify an address. In my view, that is a
design flaw.

Clay
msg88709 - (view) Author: Clay McClure (claymation) Date: 2009-06-02 02:38
On Mon, Jun 1, 2009 at 9:03 PM, pmoody <report@bugs.python.org> wrote:

>> ifconfig: 255.255.255.0/32: bad value
>>
>> That's because ipaddr wrongly appends a prefix length to all
>> ipaddr.IPv4 objects, even those representing addresses, which do not
>> have prefix lengths.
>
> I'm not sure what you're trying to do here, can you elaborate?

Let's say I have a UI that prompts users for two pieces of
information: interface address, and network mask. I then take those
two strings and make ipaddr.IPv4 objects out of them. This lets me
validate their correctness, and lets me perform convenient
calculations and tests (things the ipaddr library has done well).
Next, I take the IPv4 objects, coerce them to strings, and pass them
to ifconfig to configure an interface.

Assuming the user has supplied this information:

Interface address = '192.168.1.1'
Network mask = '255.255.255.0'

the following would get passed to ifconfig:

ifconfig en0 192.168.1.1/32 netmask 255.255.255.0/32

Clearly this is not what we expect, nor even legal. The principle of
least surprise is violated here, if nothing else.

We could work around this, of course, but why should we have to work
around our libraries when simply fixing them isn't that hard?

>> if isinstance(address, ipaddr.IPv4):
>>    if address.prefixlen != 32:
>>        raise TypeError("Expecting IP address, not network")
>> elif isinstance(address, ipaddr.IPv6):
>>    if address.prefixlen != 128:
>>        raise TypeError("Expecting IP address, not network")
>
> i'm not sure what's onerous about this code.  you're missing a
> try/except around ipaddr.IP(), but otherwise it seems fine.

Your definition of onerous apparently differs from mine :)

In my own applications, when I'm expecting a network, I use an
IPNetwork class, and when I'm expecting an address, I use an IPAddress
class. This means I can simply rely on the class constructors to do
the type checking for me. With ipaddr, I have to do the validation
myself. Simple isinstance() testing and duck typing don't work because
networks and addresses are represented (wrongly) by the same class.

> it's actually already been included, but that's beside the point.  I'm
> now asking you a second time to submit bug reports if there are issues
> which you see; perhaps these 'myriad of quirks' can be fixed, perhaps
> not.  yelling here doesn't actually do anything productive.

Rest assured, I've opened one issue and will open one or two more
before the night is out.

I'm sorry that you think "yelling" is unproductive. I happen to think
that healthy debate breeds better code.

Cheers,

Clay
msg88710 - (view) Author: pmoody (pmoody) * (Python committer) Date: 2009-06-02 03:00
On Mon, Jun 1, 2009 at 7:38 PM, Clay McClure <report@bugs.python.org> wrote:
>
> Clay McClure <clay@daemons.net> added the comment:
>
> On Mon, Jun 1, 2009 at 9:03 PM, pmoody <report@bugs.python.org> wrote:
>
>>> ifconfig: 255.255.255.0/32: bad value
>>>
>>> That's because ipaddr wrongly appends a prefix length to all
>>> ipaddr.IPv4 objects, even those representing addresses, which do not
>>> have prefix lengths.
>>
>> I'm not sure what you're trying to do here, can you elaborate?
>
> Let's say I have a UI that prompts users for two pieces of
> information: interface address, and network mask. I then take those
> two strings and make ipaddr.IPv4 objects out of them. This lets me
> validate their correctness, and lets me perform convenient
> calculations and tests (things the ipaddr library has done well).
> Next, I take the IPv4 objects, coerce them to strings, and pass them
> to ifconfig to configure an interface.
>
> Assuming the user has supplied this information:
>
> Interface address = '192.168.1.1'
> Network mask = '255.255.255.0'
>
> the following would get passed to ifconfig:
>
> ifconfig en0 192.168.1.1/32 netmask 255.255.255.0/32

I suppose that might be the case if you didn't know how to use ipaddr.
 knowing that ipaddr accepts an ipaddress/netmask, I'd pass it

my_ip = ipaddr.IP('%s/%s' % (ipaddress, netmask))

and then check for any exceptions.  I'd then ifconfig en0 str(my_ip)

> Clearly this is not what we expect, nor even legal. The principle of
> least surprise is violated here, if nothing else.
>
> We could work around this, of course, but why should we have to work
> around our libraries when simply fixing them isn't that hard?
>
>>> if isinstance(address, ipaddr.IPv4):
>>>    if address.prefixlen != 32:
>>>        raise TypeError("Expecting IP address, not network")
>>> elif isinstance(address, ipaddr.IPv6):
>>>    if address.prefixlen != 128:
>>>        raise TypeError("Expecting IP address, not network")
>>
>> i'm not sure what's onerous about this code.  you're missing a
>> try/except around ipaddr.IP(), but otherwise it seems fine.
>
> Your definition of onerous apparently differs from mine :)
>
> In my own applications, when I'm expecting a network, I use an
> IPNetwork class, and when I'm expecting an address, I use an IPAddress
> class. This means I can simply rely on the class constructors to do
> the type checking for me. With ipaddr, I have to do the validation
> myself. Simple isinstance() testing and duck typing don't work because
> networks and addresses are represented (wrongly) by the same class.

so ipaddr doing this validation for the user actually could make some
sense, but this could be fixed by something as easy

  ipaddr.IP(ip, network=False)
or
  ipaddr.IP(net, network=True)

anyway (more below)...

>> it's actually already been included, but that's beside the point.  I'm
>> now asking you a second time to submit bug reports if there are issues
>> which you see; perhaps these 'myriad of quirks' can be fixed, perhaps
>> not.  yelling here doesn't actually do anything productive.
>
> Rest assured, I've opened one issue and will open one or two more
> before the night is out.

cool, I see that you did that. as an aside, this probably isn't the
best place for continued discussion on ipaddr. ipaddr has already been
shipped with python, so i'm not sure that debate on it's inclusion is
able to influence that decision.  All of the folks who've worked on
ipaddr + the python committer are on ipaddr-py-dev@googlegroups.com
(looks like you are too), so might I suggest we continue this
discussion there?

> I'm sorry that you think "yelling" is unproductive. I happen to think
> that healthy debate breeds better code.

I think debate is healthy, too.  but I measure my success at a debate
by my ability to convince other people of my side. I find I have
better success when I listen other people and respond with respect.
yelling promotes neither of those.

Cheers,
/peter

> Cheers,
>
> Clay
>
> ----------
>
> _______________________________________
> Python tracker <report@bugs.python.org>
> <http://bugs.python.org/issue3959>
> _______________________________________
>
msg88711 - (view) Author: Martin v. Löwis (loewis) * (Python committer) Date: 2009-06-02 05:19
> Consider applications that need to validate addresses (or networks,
> but not both) supplied as user input:
> 
> address = ipaddr.IP(input)

If that is a frequent need, it would be reasonable to add an API

address = ipaddr.IP(input, allow_mask=False)

which would raise an exception if a mask was specified (as an
old-style bit mask, or in CIDR form).

> if isinstance(address, ipaddr.IPv4):
>    if address.prefixlen != 32:
>        raise TypeError("Expecting IP address, not network")
> elif isinstance(address, ipaddr.IPv6):
>    if address.prefixlen != 128:
>        raise TypeError("Expecting IP address, not network")

With the current API, you don't need to write it in such a quirky
way. Instead

if address.numhosts != 1:
   raise TypeError("Expecting IP address, not network")

would do as well.

> Given its myriad quirks

Well, you deliberately make it appear more quirky than it actually is.
msg88712 - (view) Author: Martin v. Löwis (loewis) * (Python committer) Date: 2009-06-02 05:20
> I will go ahead and open issues on code.google.com.

If you want to see them fixed in Python, please report them to this
tracker.
msg88713 - (view) Author: Clay McClure (claymation) Date: 2009-06-02 05:29
On Tue, Jun 2, 2009 at 1:21 AM, Martin v. Löwis <report@bugs.python.org> wrote:

>> I will go ahead and open issues on code.google.com.
>
> If you want to see them fixed in Python, please report them to this
> tracker.

I'd like to see the issues fixed upstream, and the library removed
from Python until it is satisfactory to the developers who will
actually use it. To my knowledge, every developer (outside of Google)
who has commented on the issue has indicated a preference for a
different API.

Thanks,

Clay
msg88717 - (view) Author: Gregory P. Smith (gregory.p.smith) * (Python committer) Date: 2009-06-02 06:11
> Consider applications that need to validate addresses (or networks,
> but not both) supplied as user input:
>
> address = ipaddr.IP(input)
>
> if isinstance(address, ipaddr.IPv4):
>    if address.prefixlen != 32:
>        raise TypeError("Expecting IP address, not network")
> elif isinstance(address, ipaddr.IPv6):
>    if address.prefixlen != 128:
>        raise TypeError("Expecting IP address, not network")

Support for this can be added (its too late for Python 3.1).  User
input validation is a good use case.  For now I suggest the simpler
code:

if '/' in input:
    raise TypeError("Expecting IP address")
address = ipaddr.IP(input)

Or for a more pedantic test prior to calling ipaddr.IP.

if re.match('^[0-9a-fA-F:.]+$', input):
    raise TypeError("Invalid characters in IP address")

Please file a feature request on bugs.python.org for this one if you
haven't already.  We could add optional parameter(s) to ipaddr.IP to
enable only accepting host addresses or network addresses in the
future.
msg88718 - (view) Author: Martin v. Löwis (loewis) * (Python committer) Date: 2009-06-02 06:18
> I'd like to see the issues fixed upstream, and the library removed
> from Python until it is satisfactory to the developers who will
> actually use it. To my knowledge, every developer (outside of Google)
> who has commented on the issue has indicated a preference for a
> different API.

That's not true - I'm outside of Google, and have not indicated such
a preference.
msg88719 - (view) Author: Clay McClure (claymation) Date: 2009-06-02 06:34
On Tue, Jun 2, 2009 at 2:18 AM, Martin v. Löwis <report@bugs.python.org> wrote:

>> I'd like to see the issues fixed upstream, and the library removed
>> from Python until it is satisfactory to the developers who will
>> actually use it. To my knowledge, every developer (outside of Google)
>> who has commented on the issue has indicated a preference for a
>> different API.
>
> That's not true - I'm outside of Google, and have not indicated such
> a preference.

You've indicated no preference either way, and have said:

"I personally have no plans for using this library, or any other IP
address library"

I should think you would seek the opinion of those developers who
actually do have plans to use an IP address library. As far as I can
tell, every developer in that category, outside of Google, that has
commented on this issue here or in python-dev has advocated a
different API.

Clay
msg88720 - (view) Author: pmoody (pmoody) * (Python committer) Date: 2009-06-02 06:51
> I should think you would seek the opinion of those developers who
> actually do have plans to use an IP address library.

That's what this has been doing for the last 8 1/2 months.

> As far as I can
> tell, every developer in that category, outside of Google, that has
> commented on this issue here or in python-dev has advocated a
> different API.

Is there some sort of conspiracy theory-ish reason that a google
software engineer might be somehow unfairly influenced?

Cheers,
/peter
msg88742 - (view) Author: Clay McClure (claymation) Date: 2009-06-02 13:38
On Tue, Jun 2, 2009 at 2:52 AM, pmoody <report@bugs.python.org> wrote:

>> As far as I can
>> tell, every developer in that category, outside of Google, that has
>> commented on this issue here or in python-dev has advocated a
>> different API.
>
> Is there some sort of conspiracy theory-ish reason that a google
> software engineer might be somehow unfairly influenced?

From reading your comments and the code, it is clear that concepts
that aren't relevant at Google have been neglected. For that reason,
developers at Google who are already familiar with ipaddr might
consider its API quite natural because of their institutionalized
thinking. But since this library is now intended for general purpose
use outside Google, I should think it is important to consult
developers outside Google who have been exposed to a broader range of
IP addressing issues. I don't believe that "good enough for Google"
ought to be our acid test.

The fact that developers outside Google seem to prefer a different API
is not new -- comments in this issue dating back several months
reflect that fact. What I don't see is a comment that explains why
their concerns were not considered.

Clay
msg88752 - (view) Author: Gregory P. Smith (gregory.p.smith) * (Python committer) Date: 2009-06-02 16:41
This issue is closed.

Please take discussion up on a mailing list.
History
Date User Action Args
2009-06-02 17:00:27belopolskysetnosy: + belopolsky
2009-06-02 16:41:25gregory.p.smithsetmessages: + msg88752
2009-06-02 13:38:48claymationsetmessages: + msg88742
2009-06-02 06:51:50pmoodysetmessages: + msg88720
2009-06-02 06:35:33claymationsetmessages: + msg88719
2009-06-02 06:18:27loewissetmessages: + msg88718
2009-06-02 06:12:35gregory.p.smithsetmessages: + msg88717
2009-06-02 05:30:12claymationsetmessages: + msg88713
2009-06-02 05:21:04loewissetmessages: + msg88712
2009-06-02 05:20:00loewissetmessages: + msg88711
2009-06-02 03:00:24pmoodysetmessages: + msg88710
2009-06-02 02:38:40claymationsetmessages: + msg88709
2009-06-02 02:15:28claymationsetmessages: + msg88707
2009-06-02 02:03:08claymationsetmessages: + msg88706
2009-06-02 01:27:42claymationsetmessages: + msg88705
2009-06-02 01:03:18pmoodysetmessages: + msg88703
2009-06-02 00:47:44claymationsetmessages: + msg88700
2009-06-02 00:05:14r.david.murraysetmessages: + msg88692
2009-06-01 23:51:35pmoodysetmessages: + msg88688
2009-06-01 23:41:18claymationsetmessages: + msg88686
2009-06-01 21:02:05r.david.murraysetnosy: + r.david.murray
messages: + msg88678
2009-06-01 20:54:53loewissetmessages: + msg88676
2009-06-01 20:51:29pmoodysetmessages: + msg88675
2009-06-01 20:41:43claymationsetmessages: + msg88673
2009-06-01 20:33:14claymationsetmessages: + msg88672
2009-06-01 17:09:19loewissetmessages: + msg88655
2009-06-01 17:00:51gregory.p.smithsetmessages: + msg88654
2009-06-01 16:39:17claymationsetnosy: + claymation
messages: + msg88653
2009-05-03 07:04:47gregory.p.smithsetstatus: open -> closed

messages: + msg87033
2009-05-02 01:00:43gvanrossumsetmessages: - msg86929
2009-05-02 00:50:27mattsmartsetfiles: + unnamed

messages: + msg86929
2009-05-02 00:48:25gregory.p.smithsetpriority: release blocker -> normal
resolution: accepted
messages: + msg86928
2009-05-01 23:50:11pitrousetmessages: + msg86926
2009-05-01 23:49:18pmoodysetmessages: + msg86925
2009-05-01 20:19:00pmoodysetmessages: + msg86903
2009-05-01 20:16:57pitrousetmessages: + msg86902
2009-05-01 20:00:52gregory.p.smithsetpriority: normal -> release blocker

messages: + msg86898
versions: - Python 2.7
2009-03-29 23:45:08gregory.p.smithsetmessages: + msg84445
2009-02-25 05:21:09gregory.p.smithsetassignee: gregory.p.smith
messages: + msg82695
2009-02-25 01:44:42pitrousetmessages: + msg82688
2009-02-24 23:06:52pmoodysetmessages: + msg82684
2009-02-04 21:53:09oubiwannsetmessages: + msg81167
2009-02-04 19:27:34loewissetmessages: + msg81151
2009-02-04 18:45:43gvanrossumsetmessages: + msg81150
2009-02-04 18:22:20oubiwannsetmessages: + msg81147
2009-02-04 18:02:12pitrousetmessages: + msg81146
2009-02-04 17:19:22exarkunsetnosy: - exarkun
2009-02-04 17:15:18drkjamsetnosy: - drkjam
2009-02-04 17:07:36gvanrossumsetmessages: + msg81144
2009-02-04 16:25:47pmoodysetmessages: + msg81141
2009-02-03 13:11:28drkjamsetmessages: + msg81050
2009-02-02 23:08:05gregory.p.smithsetnosy: + gregory.p.smith
2009-02-02 22:26:03loewissetmessages: + msg81011
2009-02-02 22:19:34loewissetmessages: + msg81010
2009-02-02 22:14:40oubiwannsetmessages: + msg81009
2009-02-02 22:08:25ezio.melottisetnosy: + ezio.melotti
2009-02-02 22:04:39gvanrossumsetmessages: + msg81007
2009-02-02 21:57:36pmoodysetmessages: + msg81006
2009-01-05 20:00:30Rhamphoryncussetnosy: + Rhamphoryncus
2009-01-05 19:21:30gvanrossumsetmessages: + msg79187
2009-01-05 18:24:38pnasratsetnosy: + pnasrat
2009-01-05 00:36:55loewissetmessages: + msg79099
2009-01-05 00:16:24pmoodysetmessages: + msg79098
2009-01-04 16:27:55drkjamsetmessages: + msg79069
2009-01-03 18:56:08pitrousetmessages: + msg78989
2009-01-03 18:46:49oubiwannsetmessages: + msg78988
2009-01-03 18:19:32pitrousetnosy: + pitrou
2009-01-03 18:12:34loewissetmessages: + msg78985
2009-01-03 18:03:23oubiwannsetnosy: + oubiwann
messages: + msg78984
2009-01-03 02:02:06hayposetnosy: - haypo
2009-01-03 00:13:26pmoodysetmessages: + msg78908
2009-01-02 16:38:11loewissetmessages: + msg78836
2009-01-02 16:07:08loewissetmessages: + msg78826
2009-01-01 12:01:45drkjamsetmessages: + msg78700
2009-01-01 02:33:13pmoodysetmessages: + msg78683
2009-01-01 02:14:26exarkunsetmessages: + msg78680
2009-01-01 02:00:16pmoodysetmessages: + msg78677
2009-01-01 01:36:36exarkunsetnosy: + exarkun
messages: + msg78675
2009-01-01 01:08:17pmoodysetmessages: + msg78673
2008-12-31 23:43:15drkjamsetnosy: + drkjam
messages: + msg78666
2008-12-22 23:58:01loewissetmessages: + msg78218
2008-12-22 22:53:14benjamin.petersonsetmessages: + msg78216
2008-10-01 09:50:41giampaolo.rodolasetnosy: + giampaolo.rodola
2008-09-30 18:27:52hayposetmessages: + msg74094
2008-09-30 18:25:32hayposetmessages: + msg74093
2008-09-30 18:25:05hayposetnosy: + haypo
messages: + msg74092
2008-09-25 14:05:17gvanrossumsetmessages: + msg73793
2008-09-25 05:53:58pmoodysetmessages: + msg73770
2008-09-25 04:07:30loewissetnosy: + loewis
messages: + msg73768
2008-09-25 00:29:18pmoodysetnosy: + pmoody
2008-09-24 23:43:41shieldssetnosy: + shields
2008-09-24 23:34:12mattsmartsetnosy: + mattsmart
2008-09-24 23:16:48benjamin.petersonsetmessages: + msg73764
2008-09-24 23:15:57gvanrossumsetmessages: + msg73763
2008-09-24 23:15:40benjamin.petersonsetnosy: + benjamin.peterson
messages: + msg73762
2008-09-24 23:14:09gvanrossumcreate