PEP 3144: IP Address Manipulation Library for the Python Standard Library
Howdy folks, I have a first draft of a PEP for including an IP address manipulation library in the python stdlib. It seems like there are a lot of really smart folks with some, ahem, strong ideas about what an IP address module should and shouldn't be so I wanted to solicit your input on this pep. the pep can be found here: http://www.python.org/dev/peps/pep-3144/ the code can be found here: http://ipaddr-py.googlecode.com/svn/branches/2.0.x/ Please let me know if you have any comments (some already coming :) Cheers, /peter
http://ipaddr-py.googlecode.com/svn/branches/2.0.x/ipaddr.py :
def IP(address, host=False, version=None): """Take an IP string/int and return an object of the correct type.
Args: ip_str: ...
The arg is 'address', not 'ip_str'. There are two classes, IPv4 and IPv6 whose __new__ never create an instance of its class, instead they create instances of other classes. Why IPv4 and IPv6 are classes and not (factory) functions (like function IP)? Oleg. -- Oleg Broytmann http://phd.pp.ru/ phd@phd.pp.ru Programmers don't die, they just GOSUB without RETURN.
On Tue, Aug 18, 2009 at 1:34 PM, Oleg Broytmann<phd@phd.pp.ru> wrote:
http://ipaddr-py.googlecode.com/svn/branches/2.0.x/ipaddr.py :
def IP(address, host=False, version=None): """Take an IP string/int and return an object of the correct type.
Args: ip_str: ...
The arg is 'address', not 'ip_str'.
d'oh, fixed.
There are two classes, IPv4 and IPv6 whose __new__ never create an instance of its class, instead they create instances of other classes. Why IPv4 and IPv6 are classes and not (factory) functions (like function IP)?
hold over from when I was trying to be too fancy. fixed as well. Cheers, /peter
Oleg. -- Oleg Broytmann http://phd.pp.ru/ phd@phd.pp.ru Programmers don't die, they just GOSUB without RETURN. _______________________________________________ Python-Dev mailing list Python-Dev@python.org http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/python-dev%40hda3.com
On Tue, Aug 18, 2009 at 01:53:36PM -0700, Peter Moody wrote:
hold over from when I was trying to be too fancy. fixed as well.
Thank you. The PEP and the code is Ok for me. Something like this should be in the stdlib. Currently I'm using IPy. Oleg. -- Oleg Broytmann http://phd.pp.ru/ phd@phd.pp.ru Programmers don't die, they just GOSUB without RETURN.
Le Tue, 18 Aug 2009 13:00:06 -0700, Peter Moody a écrit :
Howdy folks,
I have a first draft of a PEP for including an IP address manipulation library in the python stdlib. It seems like there are a lot of really smart folks with some, ahem, strong ideas about what an IP address module should and shouldn't be so I wanted to solicit your input on this pep.
When you say : « the results of the first computation should be cached and only re-generated should the object properties change » does it mean that the objects are mutable? Would it make sense to make them immutable and therefore hashable (such as, e.g., datetime objects)?
Antoine Pitrou wrote:
Le Tue, 18 Aug 2009 13:00:06 -0700, Peter Moody a écrit :
Howdy folks,
I have a first draft of a PEP for including an IP address manipulation library in the python stdlib. It seems like there are a lot of really smart folks with some, ahem, strong ideas about what an IP address module should and shouldn't be so I wanted to solicit your input on this pep.
When you say :
« the results of the first computation should be cached and only re-generated should the object properties change »
does it mean that the objects are mutable? Would it make sense to make them immutable and therefore hashable (such as, e.g., datetime objects)?
They could impelement __hash__ to behave correctly in this case. In the examples however I see:
o.broadcast IPv4Address('1.1.1.255')
this is often used but not the only valid broadcast address, in fact, any address between network address and max(address with given netmask) can be defined as broadcast. Maybe biggest or greatest would be better name for the attribute. User is then free to interpret it as broadcast if desired. The attribute network returned as address object also does not seem right. The performance hit you mention by translating the object upfront is neglegtible I'd say - for any sensible use of the object you'd need the binary form anyway. You can even use system (e.g. socket) funtions to make the translation very fast. This also safes space and allow vor verification of the input. (e.g. '255.255.255.255/32' is 18 bytes where it could be stored as 8 bytes instead (or even 5 if you use ip/prefixlength) I have a very very old implementation which even did the translation from cidr format to integer in python code (I don't say plain ;) but maybe worth a look: http://www.zope.org/Members/tino/IPPatternAuthentication/IPHelper.py/view Regards Tino
On Wed, Aug 19, 2009 at 6:47 AM, Tino Wildenhain<tino@wildenhain.de> wrote:
Antoine Pitrou wrote:
Le Tue, 18 Aug 2009 13:00:06 -0700, Peter Moody a écrit :
Howdy folks,
I have a first draft of a PEP for including an IP address manipulation library in the python stdlib. It seems like there are a lot of really smart folks with some, ahem, strong ideas about what an IP address module should and shouldn't be so I wanted to solicit your input on this pep.
When you say :
« the results of the first computation should be cached and only re-generated should the object properties change »
does it mean that the objects are mutable? Would it make sense to make them immutable and therefore hashable (such as, e.g., datetime objects)?
They could impelement __hash__ to behave correctly in this case.
In the examples however I see:
o.broadcast IPv4Address('1.1.1.255')
this is often used but not the only valid broadcast address, in fact, any address between network address and max(address with given netmask) can be defined as broadcast. Maybe biggest or greatest would be better name for the attribute. User is then free to interpret it as broadcast if desired.
The attribute network returned as address object also does not seem right.
by convention, the highest address in a given network is called the broadcast address while the lowest address is called the network address. They're also distinct addresses, as opposed to networks, hence .broadcast/.network/etc returning IPvXAddress objects. calling them .biggest and .smallest would be confusing. am I misinterpreting what you mean?
The performance hit you mention by translating the object upfront is neglegtible I'd say - for any sensible use of the object you'd need the binary form anyway. You can even use system (e.g. socket) funtions to make the translation very fast. This also safes space and allow vor verification of the input.
I'll look into using socket where I can, but the computational hit actually wasn't negligible. A common use for something like this library might be to verify that an addresses typed by a user is valid, '192.168.1.1' instead os '1921.68.1.1'; computing the extra attributes delays the return time and doesn't actually benefit the user or programmer. Cheers, /peter
(e.g. '255.255.255.255/32' is 18 bytes where it could be stored as 8 bytes instead (or even 5 if you use ip/prefixlength)
I have a very very old implementation which even did the translation from cidr format to integer in python code (I don't say plain ;) but maybe worth a look:
http://www.zope.org/Members/tino/IPPatternAuthentication/IPHelper.py/view
Regards Tino
_______________________________________________ Python-Dev mailing list Python-Dev@python.org http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/python-dev%40hda3.com
Peter Moody wrote:
On Wed, Aug 19, 2009 at 6:47 AM, Tino Wildenhain<tino@wildenhain.de> wrote:
Antoine Pitrou wrote:
Le Tue, 18 Aug 2009 13:00:06 -0700, Peter Moody a écrit :
Howdy folks,
I have a first draft of a PEP for including an IP address manipulation library in the python stdlib. It seems like there are a lot of really smart folks with some, ahem, strong ideas about what an IP address module should and shouldn't be so I wanted to solicit your input on this pep. When you say :
« the results of the first computation should be cached and only re-generated should the object properties change »
does it mean that the objects are mutable? Would it make sense to make them immutable and therefore hashable (such as, e.g., datetime objects)? They could impelement __hash__ to behave correctly in this case.
In the examples however I see:
o.broadcast IPv4Address('1.1.1.255')
this is often used but not the only valid broadcast address, in fact, any address between network address and max(address with given netmask) can be defined as broadcast. Maybe biggest or greatest would be better name for the attribute. User is then free to interpret it as broadcast if desired.
The attribute network returned as address object also does not seem right.
by convention, the highest address in a given network is called the broadcast address while the lowest address is called the network address. They're also distinct addresses, as opposed to networks, hence .broadcast/.network/etc returning IPvXAddress objects. calling them .biggest and .smallest would be confusing.
am I misinterpreting what you mean?
No, I just said its conventionally used as that but its not definition of a broadcast (in fact you can have any valid host address defined as broadcast as long as all members of the network agree on that) Since you dont want to call the attribute ususally_the_broadcast_address or something, other names which tell you about the data would seem more appropriate (like greatest)
The performance hit you mention by translating the object upfront is neglegtible I'd say - for any sensible use of the object you'd need the binary form anyway. You can even use system (e.g. socket) funtions to make the translation very fast. This also safes space and allow vor verification of the input.
I'll look into using socket where I can, but the computational hit actually wasn't negligible. A common use for something like this library might be to verify that an addresses typed by a user is valid, '192.168.1.1' instead os '1921.68.1.1'; computing the extra attributes delays the return time and doesn't actually benefit the user or programmer.
Maybe I don't quite understand your extra attributes stuff - the 32 bit integer for ipv4 IP and the netmask in either 32 bit or prefix length in 5 bits would be enough of a storage attribute. All others are just representation of the values. Storing the data as string seems a bit suboptimal since for any sensible operation with the data you'd need to do the conversion anyway. Regards Tino
No, I just said its conventionally used as that but its not definition of a broadcast (in fact you can have any valid host address defined as broadcast as long as all members of the network agree on that)
You could, but then you are violating existing protocol specifications. RFC 1122 mandates, in sections 3.2.1.3 and 3.3.6, that certain addresses MUST be understood as broadcast addresses, by all nodes (independent of configuration). I think a Python IP address library should conform to all relevant RFCs.
Since you dont want to call the attribute ususally_the_broadcast_address or something, other names which tell you about the data would seem more appropriate (like greatest)
No. I think setting the broadcast address to something else just does not need to be supported. Regards, Martin
On Wed, Aug 19, 2009 at 4:45 PM, "Martin v. Löwis" <martin@v.loewis.de>wrote:
No, I just said its conventionally used as that but its not definition of a broadcast (in fact you can have any valid host address defined as broadcast as long as all members of the network agree on that)
You could, but then you are violating existing protocol specifications.
RFC 1122 mandates, in sections 3.2.1.3 and 3.3.6, that certain addresses MUST be understood as broadcast addresses, by all nodes (independent of configuration).
I think a Python IP address library should conform to all relevant RFCs.
Yes, but section 3.3.6 also states: There is a class of hosts (4.2BSD Unix and its derivatives, but not 4.3BSD) that use non-standard broadcast address forms, substituting 0 for -1. All hosts SHOULD recognize and accept any of these non-standard broadcast addresses as the destination address of an incoming datagram. A host MAY optionally have a configuration option to choose the 0 or the -1 form of broadcast address, for each physical interface, but this option SHOULD default to the standard (-1) form. So it sounds like doing what I suggested earlier (default to [-1], allow for customization) is actually required by the RFC :-). Although it does sound like the RFC only requires that you be able to customize to [0] rather than [-1], rather than any address. In practical terms though I believe it is possible to do as Tino suggests and configure any crazy address you want to be the broadcast address (or addresses, even) for a network. I think setting the broadcast address to something else just does not need
to be supported.
It is unusual, but frankly, needing to actually do operations on broadcast addresses at all is also a pretty unusual task. Broadcast itself is a somewhat obscure corner of networking. I suspect that in many deployments that need to write significant code to deal with broadcast addresses, rather than the usual default stuff, funky configurations will actually be quite common. I would not be surprised to find that there are still some 4.2BSD VAXes somewhere doing something important, and some Python may one day be called upon to manage their networks.
[Glyph]
So it sounds like doing what I suggested earlier (default to [-1], allow for customization) is actually required by the RFC :-). Although it does sound like the RFC only requires that you be able to customize to [0] rather than [-1], rather than any address. In practical terms though I believe it is possible to do as Tino suggests and configure any crazy address you want to be the broadcast address (or addresses, even) for a network.
If you're doing this, are you really going to be specifying the broadcast address as something like network.use_broadcast_index(-2) (or even 0) and then using network.broadcast somewhere else? I just don't see that happening. [Martin]
I think setting the broadcast address to something else just does not need to be supported.
I agree. [Glyph]
It is unusual, but frankly, needing to actually do operations on broadcast addresses at all is also a pretty unusual task. Broadcast itself is a somewhat obscure corner of networking. I suspect that in many deployments that need to write significant code to deal with broadcast addresses, rather than the usual default stuff, funky configurations will actually be quite common.
I use .broadcast from IPy, and I'm not doing anything funky. All of my broadcast addresses are network[-1].
Glyph Lefkowitz wrote:
It is unusual, but frankly, needing to actually do operations on broadcast addresses at all is also a pretty unusual task. Broadcast itself is a somewhat obscure corner of networking. I suspect that in many deployments that need to write significant code to deal with broadcast addresses, rather than the usual default stuff, funky configurations will actually be quite common.
I would not be surprised to find that there are still some 4.2BSD VAXes somewhere doing something important, and some Python may one day be called upon to manage their networks.
If using a custom broadcast address rather than the standard one, don't use the ipnet.broadcast property? I'm with Martin and the PEP author here - the property can quite happily just use the conventional meaning without causing any real problems. People doing something more unusual will still be free to either create an appropriate IPAddress instance or else create an IPNetwork subclass that defines the broadcast property differently (e.g. making it the same as the network address). Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia ---------------------------------------------------------------
On Wed, 19 Aug 2009 at 08:19, Peter Moody wrote:
On Wed, Aug 19, 2009 at 6:47 AM, Tino Wildenhain<tino@wildenhain.de> wrote:
Le Tue, 18 Aug 2009 13:00:06 -0700, Peter Moody a �crit :
o.broadcast � �IPv4Address('1.1.1.255')
this is often used but not the only valid broadcast address, in fact, any address between network address and max(address with given netmask) can be defined as broadcast. Maybe biggest or greatest would be better name for the attribute. User is then free to interpret it as broadcast if desired.
The attribute network returned as address object also does not seem right.
by convention, the highest address in a given network is called the broadcast address while the lowest address is called the network address. They're also distinct addresses, as opposed to networks, hence .broadcast/.network/etc returning IPvXAddress objects. calling them .biggest and .smallest would be confusing.
am I misinterpreting what you mean?
Possibly. Tino means exactly what he said: the broadcast address does not _have_ to be the last IP, nor does the last IP _have_ to be a broadcast, though in practice they almost always are (and using the last IP as a host IP almost never works in practice in a heterogeneous network). Check out the 'broadcast' option of the ifconfig command for confirmation that the broadcast address can be any IP in the network. Of course, for that to work all hosts on the network have to agree on what the broadcast is, hence the normal convention that the broadcast is the last IP in the network. As for the 'network' attribute, if you call it 'network' IMO it should be a network data type, which would make it rather redundant. What you are actually returning is what I have normally heard called either the 'zero' of the network, or the "network number" or "network identifier"; but never just "network" (a network has to have at least an implicit netmask to be meaningful, IMO). Since you are dealing with networks as a list of addresses, perhaps you should drop the 'network' attribute, make the 'broadcast' attribute settable with a default equal to self[-1], and let the user refer to the zero element to get the zero of the network if they want it. --David
On Wed, Aug 19, 2009 at 9:21 AM, R. David Murray<rdmurray@bitdance.com> wrote:
On Wed, 19 Aug 2009 at 08:19, Peter Moody wrote:
On Wed, Aug 19, 2009 at 6:47 AM, Tino Wildenhain<tino@wildenhain.de> wrote:
Le Tue, 18 Aug 2009 13:00:06 -0700, Peter Moody a écrit :
o.broadcast
IPv4Address('1.1.1.255')
this is often used but not the only valid broadcast address, in fact, any address between network address and max(address with given netmask) can be defined as broadcast. Maybe biggest or greatest would be better name for the attribute. User is then free to interpret it as broadcast if desired.
The attribute network returned as address object also does not seem right.
by convention, the highest address in a given network is called the broadcast address while the lowest address is called the network address. They're also distinct addresses, as opposed to networks, hence .broadcast/.network/etc returning IPvXAddress objects. calling them .biggest and .smallest would be confusing.
am I misinterpreting what you mean?
Possibly. Tino means exactly what he said: the broadcast address does not _have_ to be the last IP, nor does the last IP _have_ to be a broadcast, though in practice they almost always are (and using the last IP as a host IP almost never works in practice in a heterogeneous network). Check out the 'broadcast' option of the ifconfig command for confirmation that the broadcast address can be any IP in the network. Of course, for that to work all hosts on the network have to agree on what the broadcast is, hence the normal convention that the broadcast is the last IP in the network.
As for the 'network' attribute, if you call it 'network' IMO it should be a network data type, which would make it rather redundant. What you are actually returning is what I have normally heard called either the 'zero' of the network, or the "network number" or "network identifier"; but never just "network" (a network has to have at least an implicit netmask to be meaningful, IMO).
Since you are dealing with networks as a list of addresses, perhaps you should drop the 'network' attribute, make the 'broadcast' attribute settable with a default equal to self[-1], and let the user refer to the zero element to get the zero of the network if they want it.
making the broadcast address settable (with a default to self[-1]) might be reasonable, though it is different from just about every other python implementation I've seen (IPy, ipv4.py, netaddr). I'm not sure I understand your point about the network attribute. what I'm returning with network is the subnet-id/base address of the given network. Again, .network seems to be fairly standard for naming.
--David
Peter Moody wrote:
On Wed, Aug 19, 2009 at 9:21 AM, R. David Murray<rdmurray@bitdance.com> wrote:
Possibly. Tino means exactly what he said: the broadcast address does not _have_ to be the last IP, nor does the last IP _have_ to be a broadcast, though in practice they almost always are (and using the last IP as a host IP almost never works in practice in a heterogeneous network). Check out the 'broadcast' option of the ifconfig command for confirmation that the broadcast address can be any IP in the network. Of course, for that to work all hosts on the network have to agree on what the broadcast is, hence the normal convention that the broadcast is the last IP in the network.
As for the 'network' attribute, if you call it 'network' IMO it should be a network data type, which would make it rather redundant. What you are actually returning is what I have normally heard called either the 'zero' of the network, or the "network number" or "network identifier"; but never just "network" (a network has to have at least an implicit netmask to be meaningful, IMO).
Since you are dealing with networks as a list of addresses, perhaps you should drop the 'network' attribute, make the 'broadcast' attribute settable with a default equal to self[-1], and let the user refer to the zero element to get the zero of the network if they want it.
making the broadcast address settable (with a default to self[-1]) might be reasonable, though it is different from just about every other python implementation I've seen (IPy, ipv4.py, netaddr).
I'm not sure I understand your point about the network attribute. what I'm returning with network is the subnet-id/base address of the given network. Again, .network seems to be fairly standard for naming.
I think using .network and .broadcast are pretty well understood to be the [0] and [-1] of the network address block. I don't think we want to start creating new terms or access patterns here. +1 on leaving .network and .broadcast as-is (including returning a IPvXAddress object). Eric.
On Wed, Aug 19, 2009 at 2:20 PM, Eric Smith <eric@trueblade.com> wrote:
I think using .network and .broadcast are pretty well understood to be the [0] and [-1] of the network address block. I don't think we want to start creating new terms or access patterns here.
+1 on leaving .network and .broadcast as-is (including returning a IPvXAddress object).
-1. I think 'network.number' or 'network.zero' is a lot clearer than 'network.network'. Maybe '.broadcast' would be okay, as long as it *can* be adjusted for those unusual, or maybe even only hypothetical, networks where it is not the [-1].
Glyph Lefkowitz wrote:
On Wed, Aug 19, 2009 at 2:20 PM, Eric Smith <eric@trueblade.com <mailto:eric@trueblade.com>> wrote:
I think using .network and .broadcast are pretty well understood to be the [0] and [-1] of the network address block. I don't think we want to start creating new terms or access patterns here.
+1 on leaving .network and .broadcast as-is (including returning a IPvXAddress object).
-1. I think 'network.number' or 'network.zero' is a lot clearer than 'network.network'. Maybe '.broadcast' would be okay, as long as it /can/ be adjusted for those unusual, or maybe even only hypothetical, networks where it is not the [-1].
Is there some existing library that uses .number or .zero? IPy uses .net (and .broadcast for [-1]).
Glyph Lefkowitz wrote:
-1. I think 'network.number' or 'network.zero' is a lot clearer than 'network.network'. Maybe '.broadcast' would be okay, as long as it /can/ be adjusted for those unusual, or maybe even only hypothetical, networks where it is not the [-1].
Maybe this is something that differs by country, but I have *never* heard the first address in an IP network (i.e. every bit not covered by the netmask set to zero) referred to as anything other than the "network address". Similarly, the last address (every bit not covered by the netmask set to one) is referred to as the "broadcast address", even if the relevant RFCs don't actually guarantee that. Anyone tasked to deal with a network that is sufficient unusual to break those two conventions is almost certainly going to have bigger problems than the proposed meanings for ipnet.network and ipnet.broadcast not giving the correct answer for their specific situation. And if someone does need to deal with that, then they create an appropriate subclass or use a less lightweight IP addressing library. Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia ---------------------------------------------------------------
Nick Coghlan wrote:
Maybe this is something that differs by country, but I have *never* heard the first address in an IP network (i.e. every bit not covered by the netmask set to zero) referred to as anything other than the "network address".
Ah! A change to interject a mostly pointless comment... Prior to IEN-212 [1] it wasn't standardized, the 'zero' was used and supported by the Berkeley socket library. This was a number of years ago, however (!), and I dare say the sample code is lost to antiquity.
And if someone does need to deal with that, then they create an appropriate subclass or use a less lightweight IP addressing library.
Indeed. Joel [1] <http://www.networksorcery.com/enp/ien/ien212.txt>
Joel Bender wrote:
Nick Coghlan wrote:
Maybe this is something that differs by country, but I have *never* heard the first address in an IP network (i.e. every bit not covered by the netmask set to zero) referred to as anything other than the "network address".
Ah! A change to interject a mostly pointless comment...
Prior to IEN-212 [1] it wasn't standardized, the 'zero' was used and supported by the Berkeley socket library. This was a number of years ago, however (!), and I dare say the sample code is lost to antiquity.
Ah, that would be me showing my (lack of) age then :) I was still six years or so away from getting my first computer and more than 15 years away from any formal networking training when that note was published... Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia ---------------------------------------------------------------
On Wed, Aug 19, 2009 at 02:28:38PM -0400, Glyph Lefkowitz wrote:
On Wed, Aug 19, 2009 at 2:20 PM, Eric Smith <eric@trueblade.com> wrote:
I think using .network and .broadcast are pretty well understood to be the [0] and [-1] of the network address block. I don't think we want to start creating new terms or access patterns here.
+1 on leaving .network and .broadcast as-is (including returning a IPvXAddress object).
-1. I think 'network.number' or 'network.zero' is a lot clearer than 'network.network'. Maybe '.broadcast' would be okay, as long as it *can* be adjusted for those unusual, or maybe even only hypothetical, networks where it is not the [-1]. Real life example: network with a /31 mask. There are only two hosts: 0 and 1 first host configures the other's host as broadcast address and vice versa. NOTE - broadcasts are different here! Everything works, no one ever need to address "network" address, broadcasting works as expected. It works well between two our routers. What is wrong here? It just works for two Linuxes. It emulates point-to-point. Well, some weird soft will not let you to configure that (on Windows?heh)? So just let Python be off the shame list.
Another real life examples include /32 networks on PPP. Just a point-to-point. No need for broadcasts and networks, a host just have one IP address and send all traffic via point-to-point link, no addressing is required there. This is a working dialup configuration, it works for me, it works for you, probably. It is not weird, it is common, it is used for PPPoE, for ADSL, for dialup. -- Alexey S.
I think using .network and .broadcast are pretty well understood to be the [0] and [-1] of the network address block. I don't think we want to start creating new terms or access patterns here.
+1 on leaving .network and .broadcast as-is (including returning a IPvXAddress object).
-1. I think 'network.number' or 'network.zero' is a lot clearer than 'network.network'. Maybe '.broadcast' would be okay, as long as it *can* be adjusted for those unusual, or maybe even only hypothetical, networks where it is not the [-1]. Real life example: network with a /31 mask. There are only two hosts: 0 and 1 first host configures the other's host as broadcast address and vice versa. NOTE - broadcasts are different here!
This is RFC 3021. IIUC, it does not support directed broadcast; only link-local broadcast can be used on that link. So ISTM that .broadcast should raise an exception on a /31 network. Any installation that configures the partner as the broadcast address is broken (somebody correct me if I'm wrong).
Another real life examples include /32 networks on PPP. Just a point-to-point. No need for broadcasts and networks, a host just have one IP address and send all traffic via point-to-point link, no addressing is required there. This is a working dialup configuration, it works for me, it works for you, probably. It is not weird, it is common, it is used for PPPoE, for ADSL, for dialup.
So where is that defined? Regards, Martin
I realize I'm late to this party, but this is just a naming issue, right? For any network, there are two special addresses, one with the last bits all zeros, one with the last bits all ones. We can call them A and B, or network and broadcast, or zeros and ones, or whatever we care. But their definitions are two well-defined functions for all networks (assuming a network is defined as an IP address and a number of bits), even if in an extreme case the functions return the same value. What is actually configured on a particular host to be the broadcast address is a separate issue, even if *by convention* in most cases it is given by one of the above functions -- the network object doesn't care, the configuration object is something else (and outside the scope of this PEP). IMO "real life examples" don't matter for the definitions of the functions, and I would personally be happy to name them network and broadcast, since I know their definitions and their typical uses and these match pretty closely. The expectation should be clearly set that these are pure functions though and do not imply knowledge of the configuration of any given host. --Guido On Sat, Sep 26, 2009 at 11:19 AM, "Martin v. Löwis" <martin@v.loewis.de> wrote:
I think using .network and .broadcast are pretty well understood to be the [0] and [-1] of the network address block. I don't think we want to start creating new terms or access patterns here.
+1 on leaving .network and .broadcast as-is (including returning a IPvXAddress object).
-1. I think 'network.number' or 'network.zero' is a lot clearer than 'network.network'. Maybe '.broadcast' would be okay, as long as it *can* be adjusted for those unusual, or maybe even only hypothetical, networks where it is not the [-1]. Real life example: network with a /31 mask. There are only two hosts: 0 and 1 first host configures the other's host as broadcast address and vice versa. NOTE - broadcasts are different here!
This is RFC 3021. IIUC, it does not support directed broadcast; only link-local broadcast can be used on that link.
So ISTM that .broadcast should raise an exception on a /31 network. Any installation that configures the partner as the broadcast address is broken (somebody correct me if I'm wrong).
Another real life examples include /32 networks on PPP. Just a point-to-point. No need for broadcasts and networks, a host just have one IP address and send all traffic via point-to-point link, no addressing is required there. This is a working dialup configuration, it works for me, it works for you, probably. It is not weird, it is common, it is used for PPPoE, for ADSL, for dialup.
So where is that defined?
Regards, Martin _______________________________________________ Python-Dev mailing list Python-Dev@python.org http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/guido%40python.org
-- --Guido van Rossum (home page: http://www.python.org/~guido/)
Guido van Rossum wrote:
I realize I'm late to this party, but this is just a naming issue, right?
Not really (AFAIU).
For any network, there are two special addresses, one with the last bits all zeros, one with the last bits all ones. We can call them A and B, or network and broadcast, or zeros and ones, or whatever we care. But their definitions are two well-defined functions for all networks (assuming a network is defined as an IP address and a number of bits), even if in an extreme case the functions return the same value.
For the broadcast address, it's different, since you might also use it in programming (i.e. when sending broadcasts). Now, it seems that people will typically use undirected broadcasts (INADDR_BROADCAST). However, I assume there are also applications for directed broadcasts; in this case, it would matter to know the broadcast address of a network.
What is actually configured on a particular host to be the broadcast address is a separate issue, even if *by convention* in most cases it is given by one of the above functions -- the network object doesn't care, the configuration object is something else (and outside the scope of this PEP).
It's a little bit stronger than convention; there are RFCs saying that the all-ones (-1) address has to be the broadcast address. This is like saying that it is out of scope of the socket protocol whether TCP is the IP protocol 6, and that individual hosts may do it differently - yes, they may, but then everything stops working.
IMO "real life examples" don't matter for the definitions of the functions
That I agree with.
and I would personally be happy to name them network and broadcast, since I know their definitions and their typical uses and these match pretty closely. The expectation should be clearly set that these are pure functions though and do not imply knowledge of the configuration of any given host.
That I also agree with. However, there is this issue of /31 networks, where an 8-year-old RFC specifies how to do broadcasts on these. I think RFCs should be considered wherever applicable. Regards, Martin
On Sun, Sep 27, 2009 at 12:41 AM, "Martin v. Löwis" <martin@v.loewis.de> wrote:
Guido van Rossum wrote:
I realize I'm late to this party, but this is just a naming issue, right?
Not really (AFAIU).
For any network, there are two special addresses, one with the last bits all zeros, one with the last bits all ones. We can call them A and B, or network and broadcast, or zeros and ones, or whatever we care. But their definitions are two well-defined functions for all networks (assuming a network is defined as an IP address and a number of bits), even if in an extreme case the functions return the same value.
For the broadcast address, it's different, since you might also use it in programming (i.e. when sending broadcasts).
So there is no need to look up the broadcast address in the configuration? Don't you have to look up the rest of the network configuration too? (Or otherwise how do you know your network address and the value of /N?)
Now, it seems that people will typically use undirected broadcasts (INADDR_BROADCAST). However, I assume there are also applications for directed broadcasts; in this case, it would matter to know the broadcast address of a network.
I don't know, and it seems you are not familiar with an actual case either. I would assume that apps doing such low-level work would have direct access to the complete network configuration, of which the broadcast address to use would be a separate argument. The ipaddr library seems most useful for doing manipulations and computations on addresses and networks that may bear no relationship to the current host's configuration -- e.g. off-line verification of firewall configurations, or whatever.
What is actually configured on a particular host to be the broadcast address is a separate issue, even if *by convention* in most cases it is given by one of the above functions -- the network object doesn't care, the configuration object is something else (and outside the scope of this PEP).
It's a little bit stronger than convention; there are RFCs saying that the all-ones (-1) address has to be the broadcast address.
Sure, but what is the status of those RFCs? (Plenty of RFCs are unimplemented or superseded by others etc.) In any case we seem to agree that 'broadcast' is a fine name for the 'all ones' address so I don't want to argue this point any further. :)
This is like saying that it is out of scope of the socket protocol whether TCP is the IP protocol 6, and that individual hosts may do it differently - yes, they may, but then everything stops working.
Well, except that if al hosts on a closed network were to define their alternate value in the appropriate header, then everything would work (within that closed network!), even Python (which gets the TCP value from the system header too). But I don't think that that is relevant to ipaddr, which has to be able to make decisions about arbitrary IP addresses and networks without having access to the hosts or their configurations. It can only look at the syntax.
IMO "real life examples" don't matter for the definitions of the functions
That I agree with.
and I would personally be happy to name them network and broadcast, since I know their definitions and their typical uses and these match pretty closely. The expectation should be clearly set that these are pure functions though and do not imply knowledge of the configuration of any given host.
That I also agree with.
However, there is this issue of /31 networks, where an 8-year-old RFC specifies how to do broadcasts on these. I think RFCs should be considered wherever applicable.
Considered wherever applicable, yes. I'm assuming you're talking about RFC 3021 -- which says "standards track" but I can't find whether it is actually a standard or how widespread its implementation is. It might well be obsolete by now, or widely ignored, or irrelevant outside a few drivers. Another question is whether it *always* applies when a /31 network is used. If not, then we're back to the situation where we can't know the configuration, and declaring the RFC applicable in all cases doesn't make it so. RFC 3021 adds an odd wart to the "all ones" and "all zeros" functions (or perhaps only to "all ones"?). If after further examination of the facts we find that it should be honored, then what do we do for .network and .broadcast on a /32 "network"? Is that an error or should it just return the one IP address of which the "network" consists? -- --Guido van Rossum (home page: http://www.python.org/~guido/)
For the broadcast address, it's different, since you might also use it in programming (i.e. when sending broadcasts).
So there is no need to look up the broadcast address in the configuration? Don't you have to look up the rest of the network configuration too? (Or otherwise how do you know your network address and the value of /N?)
You would have to know either the broadcast address directly, or the network (i.e. address and prefix length).
What is actually configured on a particular host to be the broadcast address is a separate issue, even if *by convention* in most cases it is given by one of the above functions -- the network object doesn't care, the configuration object is something else (and outside the scope of this PEP). It's a little bit stronger than convention; there are RFCs saying that the all-ones (-1) address has to be the broadcast address.
Sure, but what is the status of those RFCs? (Plenty of RFCs are unimplemented or superseded by others etc.)
The one that says that the broadcast address is -1 (and 0 should also be supported) is STD 3. The one that talks about 31-bit prefixes (RFC 3021) is a proposed standard.
RFC 3021 adds an odd wart to the "all ones" and "all zeros" functions (or perhaps only to "all ones"?).
To both: it allows them to be used as host addresses, even though STD 3 says that they are reserved and must not be assigned to hosts.
If after further examination of the facts we find that it should be honored, then what do we do for .network and .broadcast on a /32 "network"?
For these, I would first like to find out what their specification is. Regards, Martin
On Wed, Aug 19, 2009 at 3:20 AM, Antoine Pitrou<solipsis@pitrou.net> wrote:
Le Tue, 18 Aug 2009 13:00:06 -0700, Peter Moody a écrit :
Howdy folks,
I have a first draft of a PEP for including an IP address manipulation library in the python stdlib. It seems like there are a lot of really smart folks with some, ahem, strong ideas about what an IP address module should and shouldn't be so I wanted to solicit your input on this pep.
When you say :
« the results of the first computation should be cached and only re-generated should the object properties change »
does it mean that the objects are mutable? Would it make sense to make them immutable and therefore hashable (such as, e.g., datetime objects)?
that's a good point. I'll implement __hash__ in the BaseIP class.
_______________________________________________ Python-Dev mailing list Python-Dev@python.org http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/python-dev%40hda3.com
Peter Moody wrote:
On Wed, Aug 19, 2009 at 3:20 AM, Antoine Pitrou<solipsis@pitrou.net> wrote:
Le Tue, 18 Aug 2009 13:00:06 -0700, Peter Moody a écrit :
Howdy folks,
I have a first draft of a PEP for including an IP address manipulation library in the python stdlib. It seems like there are a lot of really smart folks with some, ahem, strong ideas about what an IP address module should and shouldn't be so I wanted to solicit your input on this pep. When you say :
« the results of the first computation should be cached and only re-generated should the object properties change »
does it mean that the objects are mutable? Would it make sense to make them immutable and therefore hashable (such as, e.g., datetime objects)?
that's a good point. I'll implement __hash__ in the BaseIP class.
But are the objects mutable? I haven't had time to deep dive on this yet, but I'd like to. I also use IPy and would like to some this in the stdlib. Eric.
On Wed, Aug 19, 2009 at 8:39 AM, Eric Smith<eric@trueblade.com> wrote:
Peter Moody wrote:
On Wed, Aug 19, 2009 at 3:20 AM, Antoine Pitrou<solipsis@pitrou.net> wrote:
Le Tue, 18 Aug 2009 13:00:06 -0700, Peter Moody a écrit :
Howdy folks,
I have a first draft of a PEP for including an IP address manipulation library in the python stdlib. It seems like there are a lot of really smart folks with some, ahem, strong ideas about what an IP address module should and shouldn't be so I wanted to solicit your input on this pep.
When you say :
« the results of the first computation should be cached and only re-generated should the object properties change »
does it mean that the objects are mutable? Would it make sense to make them immutable and therefore hashable (such as, e.g., datetime objects)?
that's a good point. I'll implement __hash__ in the BaseIP class.
But are the objects mutable? I haven't had time to deep dive on this yet, but I'd like to. I also use IPy and would like to some this in the stdlib.
you can't set them directly, if that's what you mean.
import ipaddr o = ipaddr.IPv4Network('1.1.1.0/24') o.broadcast IPv4Address('1.1.1.255') o.network IPv4Address('1.1.1.0') o.broadcast = ipaddr.IPv4Address('1.1.1.127') Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: can't set attribute o.prefixlen = 25 o.broadcast IPv4Address('1.1.1.127')
Eric.
Peter Moody wrote:
you can't set them directly, if that's what you mean.
import ipaddr o = ipaddr.IPv4Network('1.1.1.0/24') o.broadcast IPv4Address('1.1.1.255') o.network IPv4Address('1.1.1.0') o.broadcast = ipaddr.IPv4Address('1.1.1.127') Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: can't set attribute o.prefixlen = 25 o.broadcast IPv4Address('1.1.1.127')
IPAddress instances should definitely be hashable, but as long as "prefixlen" is mutable, IPNetwork instances should *not* be hashable, since their value can change. If prefixlen was made read only, then IPNetwork instances could also be made hashable. In that case, changing the prefix length would then have to be done by creating a new instance. Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia ---------------------------------------------------------------
On Wed, Aug 19, 2009 at 2:44 PM, Nick Coghlan<ncoghlan@gmail.com> wrote:
Peter Moody wrote:
you can't set them directly, if that's what you mean.
import ipaddr o = ipaddr.IPv4Network('1.1.1.0/24') o.broadcast IPv4Address('1.1.1.255') o.network IPv4Address('1.1.1.0') o.broadcast = ipaddr.IPv4Address('1.1.1.127') Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: can't set attribute o.prefixlen = 25 o.broadcast IPv4Address('1.1.1.127')
IPAddress instances should definitely be hashable, but as long as "prefixlen" is mutable, IPNetwork instances should *not* be hashable, since their value can change.
If prefixlen was made read only, then IPNetwork instances could also be made hashable. In that case, changing the prefix length would then have to be done by creating a new instance.
ah, I see. I'll make this fix and I think this might actually simplify the code. just to double check, it's fine for IPNetwork to remain hashable if set_prefix() actually returned a new object, correct?
Cheers, Nick.
-- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia ---------------------------------------------------------------
On Aug 19, 2009, at 6:01 PM, Peter Moody wrote:
just to double check, it's fine for IPNetwork to remain hashable if set_prefix() actually returned a new object, correct?
The name would be confusing, though. Perhaps using_prefix() would be more clear. -Fred -- Fred Drake <fdrake at acm.org>
Fred Drake wrote:
On Aug 19, 2009, at 6:01 PM, Peter Moody wrote:
just to double check, it's fine for IPNetwork to remain hashable if set_prefix() actually returned a new object, correct?
The name would be confusing, though. Perhaps using_prefix() would be more clear.
I think you'd be better off either doing this with an optional parameter to __init__, or a class method factory function (maybe from_prefix or similar). I don't see why it should be a method on an existing object.
On Wed, Aug 19, 2009 at 9:07 PM, Eric Smith<eric@trueblade.com> wrote:
Fred Drake wrote:
On Aug 19, 2009, at 6:01 PM, Peter Moody wrote:
just to double check, it's fine for IPNetwork to remain hashable if set_prefix() actually returned a new object, correct?
The name would be confusing, though. Perhaps using_prefix() would be more clear.
I think you'd be better off either doing this with an optional parameter to __init__, or a class method factory function (maybe from_prefix or similar). I don't see why it should be a method on an existing object.
while not the the prettiest, you can already (ignoring the set_prefix) do something like:
newobject = ipaddr.IP(str(o.network) + "/new prefix")
Is this sufficient?
Peter Moody wrote:
while not the the prettiest, you can already (ignoring the set_prefix) do something like:
newobject = ipaddr.IP(str(o.network) + "/new prefix")
Is this sufficient?
At this point, that is probably fine. If it comes up often enough to be worth providing a cleaner interface then it is easier to add that later. Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia ---------------------------------------------------------------
Le Wed, 19 Aug 2009 08:35:15 -0700, Peter Moody a écrit :
does it mean that the objects are mutable? Would it make sense to make them immutable and therefore hashable (such as, e.g., datetime objects)?
that's a good point. I'll implement __hash__ in the BaseIP class.
It is a common practice that only immutable objects define a meaningful __hash__ method. The reason is that dicts and sets (and perhaps other structures) cache the hash value instead of calling __hash__ again and again. If you stick a mutable with a meaningful __hash__ in a dict, and then modify the mutable object, lookups will give the wrong results (they will be based on the old, stale hash value). It seems to me that hashability is a more desireable property of IP objects than modifiability. I don't see any reason to modify an IP object after having created it (rather than creating a new object). Regards Antoine.
-On [20090818 22:15], Peter Moody (peter@hda3.com) wrote:
I have a first draft of a PEP for including an IP address manipulation library in the python stdlib. It seems like there are a lot of really smart folks with some, ahem, strong ideas about what an IP address module should and shouldn't be so I wanted to solicit your input on this pep.
the pep can be found here:
No chance at the moment to test/look through the code, so please excuse any obvious ones, I'm basing my comments on the PEP. Some elaboration on handling ipv4 mapped addresses would be nice, e.g. ::ffff:c000:280 and/or ::ffff:192.168.0.128 Some IPv6 examples would also help the PEP I think. Especially on how 0 compression is handled in addresses. Maybe show ipv4 examples on non-class boundaries, e.g. /23 instead of /24, so people are more convinced it handles CIDR properly. Clarification on whether this library will support converting a sequence of networks into another sequence where the networks which comprise consecutive netblocks will be collapsed in a new entry. E.g. 2 /24s that are neighbours will be represented as one /23. I realise some might be answered by the last paragraph of your PEP, but it would be nice to know what you consider essential and what not. -- Jeroen Ruigrok van der Werven <asmodai(-at-)in-nomine.org> / asmodai イェルーン ラウフロック ヴァン デル ウェルヴェン http://www.in-nomine.org/ | http://www.rangaku.org/ | GPG: 2EAC625B They have learned nothing, and forgotten nothing...
On Thu, Aug 20, 2009 at 6:46 AM, Jeroen Ruigrok van der Werven<asmodai@in-nomine.org> wrote:
-On [20090818 22:15], Peter Moody (peter@hda3.com) wrote:
I have a first draft of a PEP for including an IP address manipulation library in the python stdlib. It seems like there are a lot of really smart folks with some, ahem, strong ideas about what an IP address module should and shouldn't be so I wanted to solicit your input on this pep.
the pep can be found here:
No chance at the moment to test/look through the code, so please excuse any obvious ones, I'm basing my comments on the PEP.
Some elaboration on handling ipv4 mapped addresses would be nice, e.g. ::ffff:c000:280 and/or ::ffff:192.168.0.128
Some IPv6 examples would also help the PEP I think. Especially on how 0 compression is handled in addresses.
Maybe show ipv4 examples on non-class boundaries, e.g. /23 instead of /24, so people are more convinced it handles CIDR properly.
Clarification on whether this library will support converting a sequence of networks into another sequence where the networks which comprise consecutive netblocks will be collapsed in a new entry. E.g. 2 /24s that are neighbours will be represented as one /23.
I realise some might be answered by the last paragraph of your PEP, but it would be nice to know what you consider essential and what not.
I've updated the pep with lots of examples; most of the stuff you're asking for is already supported, I just didn't do a good job explaining it. A few things are pending review. Cheers, /peter
-- Jeroen Ruigrok van der Werven <asmodai(-at-)in-nomine.org> / asmodai イェルーン ラウフロック ヴァン デル ウェルヴェン http://www.in-nomine.org/ | http://www.rangaku.org/ | GPG: 2EAC625B They have learned nothing, and forgotten nothing...
-On [20090820 20:19], Peter Moody (peter@hda3.com) wrote:
I've updated the pep with lots of examples; most of the stuff you're asking for is already supported, I just didn't do a good job explaining it. A few things are pending review.
Thanks for that Peter! -- Jeroen Ruigrok van der Werven <asmodai(-at-)in-nomine.org> / asmodai イェルーン ラウフロック ヴァン デル ウェルヴェン http://www.in-nomine.org/ | http://www.rangaku.org/ | GPG: 2EAC625B Earth to earth, ashes to ashes, dust to dust...
The pep has been updated with the excellent suggestions thus far. Are there any more? Cheers, /peter On Tue, Aug 18, 2009 at 1:00 PM, Peter Moody<peter@hda3.com> wrote:
Howdy folks,
I have a first draft of a PEP for including an IP address manipulation library in the python stdlib. It seems like there are a lot of really smart folks with some, ahem, strong ideas about what an IP address module should and shouldn't be so I wanted to solicit your input on this pep.
the pep can be found here:
http://www.python.org/dev/peps/pep-3144/
the code can be found here:
http://ipaddr-py.googlecode.com/svn/branches/2.0.x/
Please let me know if you have any comments (some already coming :)
Cheers, /peter
On Thu, Aug 20, 2009 at 2:00 PM, Peter Moody<peter@hda3.com> wrote: The pep has been updated with the excellent suggestions thus far.
Are there any more?
Thanks for writing the PEP. I tried a few of the common scenarios that I use at work. Disclaimer: my comments are based on my work environment. I was surprised that IP('172.16.1.1') returned IPv4Address('172.16.1.1/32') instead of IPv4Address('172.16.1.1'). I know I can change the behavior by using host=True, but then IP('172.16.1.1/24', host=True) will raise an error. It makes more sense, at least to me, that if I input just an IP address, I get an IP address back. I would prefer that IP('172.16.1.1/32') return an IPv4Network and IP('172.16.1.1') return an IPv4Address. Would it be possible to provide an iterator that returns just the valid host IP addresses (minus the network and broadcast addresses)? "for i in IPv4Network('172.16.1.0/28')" and "for in in IPv4Network('172.16.1.0/28').iterhosts()" both return all 16 IP addresses. I normally describe 172.16.1.0/28 as consisting of one network address, 14 host addresses, and one broadcast address. I would prefer that "for i in IPv4Network('172.16.1.0/28')" return all IP addresses and that "for in in IPv4Network('172.16.1.0/28').iterhosts()" exclude the network and broadcast addresses. I think creating a list of IP addresses that can be assigned to devices on a network is a common task. Can .subnet() be enhanced to accept masks? For example, IPv4Network('172.16.0.0/16').subnet('/19') would return the eight /19 subnets. What about supporting multiple parameters to subnet? I frequently need to create complex subnet layouts. The following subnet layout is NOT made up! 172.16.0.0/22
172.16.0.0/23
172.16.2.0/25
172.16.2.128/26 172.16.2.192/26
172.16.3.0/28 172.16.3.16/28 >>172.16.3.32/30 >>172.16.3.36/30 >>172.16.3.40/30 >>172.16.3.44/30 >>172.16.3.48/30 >>172.16.3.52/30 >>172.16.3.56/30 >>172.16.3.60/30 >>>>172.16.3.64/32 .... >>>>172.16.3.79/32 172.16.3.80/28 172.16.3.96/28 172.16.3.112/28 172.16.3.128/27 172.16.3.160/27 172.16.3.192/26
A possible syntax would be: .subnet((1,'/23'),(1,'/25'),(2,'/26'),(2,'/28'),(8,'/30'),(16,'/32'),(3,'/28'),(2,'/27'),(1,'/26')) Note: I am willing to provide patches to implement my suggestions. I just won't have much time over the next couple weeks. casevh
Cheers, /peter
On Tue, Aug 18, 2009 at 1:00 PM, Peter Moody<peter@hda3.com> wrote:
Howdy folks,
I have a first draft of a PEP for including an IP address manipulation library in the python stdlib. It seems like there are a lot of really smart folks with some, ahem, strong ideas about what an IP address module should and shouldn't be so I wanted to solicit your input on this pep.
the pep can be found here:
http://www.python.org/dev/peps/pep-3144/
the code can be found here:
http://ipaddr-py.googlecode.com/svn/branches/2.0.x/
Please let me know if you have any comments (some already coming :)
Cheers, /peter
_______________________________________________ Python-Dev mailing list Python-Dev@python.org http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/casevh%40gmail.com
On Thu, Aug 20, 2009 at 10:15 PM, Case Vanhorsen<casevh@gmail.com> wrote:
On Thu, Aug 20, 2009 at 2:00 PM, Peter Moody<peter@hda3.com> wrote: The pep has been updated with the excellent suggestions thus far.
Are there any more?
Thanks for writing the PEP.
I tried a few of the common scenarios that I use at work. Disclaimer: my comments are based on my work environment.
I was surprised that IP('172.16.1.1') returned IPv4Address('172.16.1.1/32') instead of IPv4Address('172.16.1.1'). I know I can change the behavior by using host=True, but then IP('172.16.1.1/24', host=True) will raise an error. It makes more sense, at least to me, that if I input just an IP address, I get an IP address back. I would prefer that IP('172.16.1.1/32') return an IPv4Network and IP('172.16.1.1') return an IPv4Address.
I think you mean that it returns an IPv4Network object (not IPv4Address). My suggestion there is that if you know you're dealing with an address, use one of the IPvXAddress classes (or pass host=True to the IP function). IP is just a helper function and defaulting to a network with a /32 prefix seems relatively common. Knowing that my experience may not always be the most common, I can change this behavior if it's indeed confusing, but in my conversations with others and in checking out the current state of ip address libraries, this seems to be a perfectly acceptable default.
Would it be possible to provide an iterator that returns just the valid host IP addresses (minus the network and broadcast addresses)? "for i in IPv4Network('172.16.1.0/28')" and "for in in IPv4Network('172.16.1.0/28').iterhosts()" both return all 16 IP addresses. I normally describe 172.16.1.0/28 as consisting of one network address, 14 host addresses, and one broadcast address. I would prefer that "for i in IPv4Network('172.16.1.0/28')" return all IP addresses and that "for in in IPv4Network('172.16.1.0/28').iterhosts()" exclude the network and broadcast addresses. I think creating a list of IP addresses that can be assigned to devices on a network is a common task.
this is a good idea and I'll implement this. .iterhosts() for subnet - (network|broadcast) and .iterallhosts() for the entire subnet (in my testing, looping over an iterator was actually reasonably faster than just for i in IP(network):, so I'll support iterators for both)
Can .subnet() be enhanced to accept masks? For example, IPv4Network('172.16.0.0/16').subnet('/19') would return the eight /19 subnets.
This seems like an easy win. I'll implement this too.
What about supporting multiple parameters to subnet? I frequently need to create complex subnet layouts. The following subnet layout is NOT made up!
I believe it, we have equally odd subnet assignments at work. [snip]
A possible syntax would be: .subnet((1,'/23'),(1,'/25'),(2,'/26'),(2,'/28'),(8,'/30'),(16,'/32'),(3,'/28'),(2,'/27'),(1,'/26'))
Note: I am willing to provide patches to implement my suggestions. I just won't have much time over the next couple weeks.
I'm happy reviewing/accepting patches to ipaddr. I'd worry a bit about the complexity required for this, but I'm open-minded.
casevh
Cheers, /peter
On Tue, Aug 18, 2009 at 1:00 PM, Peter Moody<peter@hda3.com> wrote:
Howdy folks,
I have a first draft of a PEP for including an IP address manipulation library in the python stdlib. It seems like there are a lot of really smart folks with some, ahem, strong ideas about what an IP address module should and shouldn't be so I wanted to solicit your input on this pep.
the pep can be found here:
http://www.python.org/dev/peps/pep-3144/
the code can be found here:
http://ipaddr-py.googlecode.com/svn/branches/2.0.x/
Please let me know if you have any comments (some already coming :)
Cheers, /peter
_______________________________________________ Python-Dev mailing list Python-Dev@python.org http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/casevh%40gmail.com
Peter Moody wrote: this is a good idea and I'll implement this. .iterhosts() for subnet
- (network|broadcast) and .iterallhosts() for the entire subnet (in my testing, looping over an iterator was actually reasonably faster than just for i in IP(network):, so I'll support iterators for both)
I would suggest just changing __iter__ to be the equivalent of the current iterhosts() and then changing iterhosts() as described. Such a change would would also fix the thread safety and nested iteration problems problems suffered by the current __iter__ implementation. I haven't executed the following, but from reading the code I am confident they would behave as a I describe in the comments: # With the current implementation, this is an infinite loop net = IPv4Network("192.168.2.0") for x in net: iter(net) # And this only runs the inner loop once for x in net: for y in net: pass Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia ---------------------------------------------------------------
Peter Moody wrote:
On Thu, Aug 20, 2009 at 10:15 PM, Case Vanhorsen<casevh@gmail.com> wrote:
I was surprised that IP('172.16.1.1') returned IPv4Address('172.16.1.1/32') instead of IPv4Address('172.16.1.1'). I know I can change the behavior by using host=True, but then IP('172.16.1.1/24', host=True) will raise an error. It makes more sense, at least to me, that if I input just an IP address, I get an IP address back. I would prefer that IP('172.16.1.1/32') return an IPv4Network and IP('172.16.1.1') return an IPv4Address.
I think you mean that it returns an IPv4Network object (not IPv4Address). My suggestion there is that if you know you're dealing with an address, use one of the IPvXAddress classes (or pass host=True to the IP function). IP is just a helper function and defaulting to a network with a /32 prefix seems relatively common.
Knowing that my experience may not always be the most common, I can change this behavior if it's indeed confusing, but in my conversations with others and in checking out the current state of ip address libraries, this seems to be a perfectly acceptable default.
The IP() helper function actually bothers me a bit - it's a function where the return *type* depends on the parameter *value*. While switching between IPv4 and IPv6 based on value is probably a necessary behaviour, perhaps it would be possible to get rid of the "host=True" ugliness and instead have two separate helper functions: IP() - returns either IPv4Address or IPv6Address IPNetwork() - returns either IPv4Network or IPv6Network Both would still accept a version argument, allowing programmatic control of which version to accept. If an unknown version is passed then some kind of warning or error should be emitted rather than the current silent fallback to attempting to guess the version based on the value. I would suggest removing the corresponding IPv4 and IPv6 helper functions altogether. My rationale for the above is that hosts and networks are *not* the same thing. For any given operation, the programmer should know whether they want a host or a network and ask for whichever one they want. The IPv4/IPv6 distinction, on the other hand, is something that a lot of operations are going to be neutral about, so it makes sense to deal with the difference implicitly. Other general comments: - the module appears to have quite a few isinstance() checks against non-abstract base classes. Either these instance checks should all be removed (relying on pure duck-typing instead) or else the relevant classes should be turned into ABCs. (Note: this comment doesn't apply to the type dispatch in the constructor methods) - the reference implementation has aliased "CamelCase" names with the heading "backwards compatibility". This is inappropriate for a standard library submission (although I can see how it would be useful if you were already using a different IP address library). - isinstance() accepts a tuple of types, so isinstance(address, (int, long)) is a shorter way of writing "isinstance(address, int) or isinstance(address, long)". The former also has the virtue of executing faster. However, an even better approach would be to use operator.index() in order to accept all integral types rather than just the builtin ones. Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia ---------------------------------------------------------------
On Fri, Aug 21, 2009 at 4:41 PM, Nick Coghlan<ncoghlan@gmail.com> wrote:
Peter Moody wrote:
On Thu, Aug 20, 2009 at 10:15 PM, Case Vanhorsen<casevh@gmail.com> wrote:
I was surprised that IP('172.16.1.1') returned IPv4Address('172.16.1.1/32') instead of IPv4Address('172.16.1.1'). I know I can change the behavior by using host=True, but then IP('172.16.1.1/24', host=True) will raise an error. It makes more sense, at least to me, that if I input just an IP address, I get an IP address back. I would prefer that IP('172.16.1.1/32') return an IPv4Network and IP('172.16.1.1') return an IPv4Address.
I think you mean that it returns an IPv4Network object (not IPv4Address). My suggestion there is that if you know you're dealing with an address, use one of the IPvXAddress classes (or pass host=True to the IP function). IP is just a helper function and defaulting to a network with a /32 prefix seems relatively common.
Knowing that my experience may not always be the most common, I can change this behavior if it's indeed confusing, but in my conversations with others and in checking out the current state of ip address libraries, this seems to be a perfectly acceptable default.
The IP() helper function actually bothers me a bit - it's a function where the return *type* depends on the parameter *value*. While switching between IPv4 and IPv6 based on value is probably a necessary behaviour, perhaps it would be possible to get rid of the "host=True" ugliness and instead have two separate helper functions:
IP() - returns either IPv4Address or IPv6Address IPNetwork() - returns either IPv4Network or IPv6Network
IPAddress() and IPNetwork seem a little less confusing. I'll get rid of IP() since it seems to be the source of a fair bit of confusion. I've added this to the pep3144 change. need to change the pep to reflect this now.
Both would still accept a version argument, allowing programmatic control of which version to accept. If an unknown version is passed then some kind of warning or error should be emitted rather than the current silent fallback to attempting to guess the version based on the value.
I would suggest removing the corresponding IPv4 and IPv6 helper functions altogether.
done.
My rationale for the above is that hosts and networks are *not* the same thing. For any given operation, the programmer should know whether they want a host or a network and ask for whichever one they want. The IPv4/IPv6 distinction, on the other hand, is something that a lot of operations are going to be neutral about, so it makes sense to deal with the difference implicitly.
makes sense to me.
Other general comments:
- the module appears to have quite a few isinstance() checks against non-abstract base classes. Either these instance checks should all be removed (relying on pure duck-typing instead) or else the relevant classes should be turned into ABCs. (Note: this comment doesn't apply to the type dispatch in the constructor methods)
I'll look through this.
- the reference implementation has aliased "CamelCase" names with the heading "backwards compatibility". This is inappropriate for a standard library submission (although I can see how it would be useful if you were already using a different IP address library).
this is for legacy reasons (how it's used at work). it's fully expected that those will disappear if/when this is accepted.
- isinstance() accepts a tuple of types, so isinstance(address, (int, long)) is a shorter way of writing "isinstance(address, int) or isinstance(address, long)". The former also has the virtue of executing faster. However, an even better approach would be to use operator.index() in order to accept all integral types rather than just the builtin ones.
I can easily make the change to checking tuples. I'd have to look further at the operator.index() to see what's required.
Cheers, Nick.
-- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia ---------------------------------------------------------------
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 :- http://netaddr.googlecode.com/svn/branches/exp_0.7.x_ip_only 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 difficult." 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 admirably. 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 improvement. 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 :-
collapse_address_list([IPv4Address('1.1.1.1'), IPv6Address('::1.1.1.1')]) [IPv4Network('1.1.1.1/32')]
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 :- http://code.google.com/p/ipaddr-py/issues/detail?id=18 Compare this with netaddr's behaviour :-
cidr_merge([IPAddress('1.1.1.1'), IPAddress('::1.1.1.1')]) [IPNetwork('1.1.1.1/32'), IPNetwork('::1.1.1.1/128')]
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) IPNetwork('10.0.0.0/8')
netaddr also handles classful IP address logic, still pervasive throughout modern IP stacks :-
IPNetwork('192.168.0.1', True) IPNetwork('192.168.0.1/24')
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. Regards, 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?
On Mon, Aug 24, 2009 at 3:24 PM, DrKJam<drkjam@gmail.com> wrote:
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.
Hi David, is this what passes for serious debate? there's more passive aggressive condescension in here than a teenager's diary. I'll try to respond with a little more civility than you managed (apologies, present paragraph excluded). As it was left in early June, a pep and design modifications were requested before ipaddr would be considered for inclusion, but if this is going to start *another* drawn out ipaddr/netaddr thread, perhaps the mailman admin(s) could setup a new SIG list for this. I personally hope that's not required; yours has been the only dissenting email and I believe I respond to all of your major points here.
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 :-
http://netaddr.googlecode.com/svn/branches/exp_0.7.x_ip_only
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 difficult."
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,
I think you mean refuse, b/c this certainly wasn't the case when I started writing ipaddr. IPy existed, but it was far too heavyweight and restrictive for what I needed (no disrespect to the author(s) intended). I believe I've an email or two from you wherein you indicate the same.
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!
yes, netaddr has sped up quite a bit. It's still slower in many cases as well. But again, who's timing?
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 admirably.
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 improvement.
I'm not sure what point you're trying to make here. I didn't say it was impossible, I inferred that there are easier ways. having used code which crams both types into one object, I found it to be cludgey and complicated so I designed something different. and as a hardly partial observer, I'll add the explicit address version you can pass to the IPAddress class, but not the IPNetwork class, is, odd. it actually seems to slow down object creation (~5%) except in the case of an int arg (your default is about twice as slow).
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 :-
collapse_address_list([IPv4Address('1.1.1.1'), IPv6Address('::1.1.1.1')]) [IPv4Network('1.1.1.1/32')]
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 :-
http://code.google.com/p/ipaddr-py/issues/detail?id=18
Compare this with netaddr's behaviour :-
cidr_merge([IPAddress('1.1.1.1'), IPAddress('::1.1.1.1')]) [IPNetwork('1.1.1.1/32'), IPNetwork('::1.1.1.1/128')]
That's more like it.
OUCH! indeed. I'm not even sure that this is a nice corner case feature, summarizing a single list of mixed ip type objects. with an extra line or two, this can be done in ipaddr, though 'tis true that we should now raise an exception and don't (it appears to be something that was introduced recently). If this is a feature for which developers are clamoring, I'm all over it. Yours is the first email I've heard mention 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.
this basically smacks of more petty attackery from the start. so I'll reply with, "it's just you". if you want to debate the merits of GOF strategy vs. multiple inheritance, fine. the class inheritance in ipaddr is very clean, and leaves very little code duplication. The classes are very clearly named and laid out, and in general are much easier to follow than the strategy method you've chosen for netaddr.
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.
you might've missed the discussions thus far, but that's basically what ipaddr does at this point.
5) The ipaddr library is also missing options for expanding various (exceedingly common) IP abbreviations.
from netaddr import IPNetwork
IPNetwork('10/8', True) IPNetwork('10.0.0.0/8')
netaddr also handles classful IP address logic, still pervasive throughout modern IP stacks :-
IPNetwork('192.168.0.1', True) IPNetwork('192.168.0.1/24')
Note that these options are disabled by default, to keep up the speed of the IPNetwork constructor up for more normal cases.
these seem like corner case features for the sake of having features, you don't even seem to put much stock in them. FWIW, I've never seen a request for something similar. I may say '10 slash 8', but I mean, '10.0.0.0/8'. I'm missing the utility here, but I'm open to reasoned arguments.
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.
I'm always open to serious debate, and patches/bug reports (apologies for missing your earlier issue. I'm not sure if you were aware, but ipaddr was undergoing a major re-write at the time and I never got around to following up). Your email however, like many of your previous ones, was not an opening to a serious debate.
Regards,
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?
There's A link to A patch (singular, both times), which has already been applied. This link exists b/c, at the time I last updated the PEP, the patch hadn't been applied as it was still being reviewed. I prefer having changes to ipaddr reviewed by people before submitting them (as opposed to your lone submitter model); in general, that leads to fewer bugs like the following:
help(netaddr.IPNetwork.__init__) Help on method __init__ in module netaddr.ip:
__init__(self, addr, implicit_prefix=False) unbound netaddr.ip.IPNetwork method Constructor. @param addr: an IPv4 or IPv6 address with optional CIDR prefix, netmask or hostmask. May be an IP address in representation (string) format, an integer or another IP object (copy construction). @param implicit_prefix: if True, the constructor uses classful IPv4 rules to select a default prefix when one is not provided. If False it uses the length of the IP address version. (default: False).
netaddr.IPNetwork(1) Traceback (most recent call last): File "<stdin>", line 1, in <module> File "./netaddr/ip/__init__.py", line 632, in __init__ prefix, suffix = addr.split('/') AttributeError: 'int' object has no attribute 'split'
vs.
import ipaddr ipaddr.IPNetwork(1) IPv4Network('0.0.0.1/32')
Did you have any other comments on the PEP? Cheers, /peter
_______________________________________________ Python-Dev mailing list Python-Dev@python.org http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/python-dev%40hda3.com
On Mon, Aug 24, 2009 at 9:54 PM, Peter Moody<peter@hda3.com> wrote:
I personally hope that's not required; yours has been the only dissenting email and I believe I respond to all of your major points here.
Silence is not assent. ipaddr looks like a reasonable library from here, but AFAIK it's not widely used outside of google. I don't know if it's reasonable to want some amount public usage before a brand-new API goes into the standard library, but such use is more likely to uncover API flaws or quirks than a PEP. -jake
ipaddr looks like a reasonable library from here, but AFAIK it's not widely used outside of google. I don't know if it's reasonable to want some amount public usage before a brand-new API goes into the standard library, but such use is more likely to uncover API flaws or quirks than a PEP.
OTOH, the PEP process *is* the stronger of the two approaches, allowing people to provide explicit opinions even if (and especially if) they dislike the technology entirely (whereas for an external module, they would just ignore it). If they refuse the comment, they can't complain when it gets added to the standard library - they can still chose to ignore it, then, of course (just as many people ignore xml.dom). In the specific case, I'm not worried about timing. Either 2.7 or 3.2 are still a year ahead, which should give people plenty of time to experiment. OTTH, I *like* people to comment strongly on the PEP, in particular if they are authors of competing libraries. It's no surprise that they get emotional when their hard work won't be appropriately honored in the long run - and if they believe there is something wrong with the technology being proposed (rather than just the words used to describe it), they are probably right. I said it before - this is not going to be a fast acceptance path of a library that gets accepted just because GvR works at google. People of competing libraries *could* write competing PEPs if they wanted to see their library incorporated instead - or they can just state that they don't want *this* library to be incorporated for specific technical reasons. Regards, Martin
2009/8/25 Peter Moody <peter@hda3.com>
On Mon, Aug 24, 2009 at 3:24 PM, DrKJam<drkjam@gmail.com> wrote:
[SNIP]
As it was left in early June, a pep and design modifications were requested before ipaddr would be considered for inclusion, but if this is going to start *another* drawn out ipaddr/netaddr thread, perhaps the mailman admin(s) could setup a new SIG list for this. I personally hope that's not required; yours has been the only dissenting email and I believe I respond to all of your major points here.
The PEP process is the perfect forum for spending some time scrutinizing and discussing this topic in more detail. I will be raising further points in future when I've had time to fully evaluate both the PEP and the reference implementation of ipaddr. At this stage, it is premature to assume the reference implementation provided along with the PEP is necessarily complete, only requiring a few bug fixes to get through the approval process.
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 :-
http://netaddr.googlecode.com/svn/branches/exp_0.7.x_ip_only
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 difficult."
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,
I think you mean refuse,
No, I meant refute.
b/c this certainly wasn't the case when I started writing ipaddr. IPy existed, but it was far too heavyweight and restrictive for what I needed (no disrespect to the author(s) intended). I believe I've an email or two from you wherein you indicate the same.
The comment made on IPy, to which I believe you are referring, was in response to you incorrectly comparing netaddr and IPy's implementation (assuming conditional logic was used within each method to support IP versioning). As already stated netaddr gets around this with a strategy design pattern approach (apologies to readers for using the "Gang of Four" acronym with regard to this). IPy is heavyweight? How so? It is a mere 1200 lines including comments and deals with IPv4 and IPv6 addressing, much like ipaddr (albeit with fewer features). There are certainly issues you could raise against it (otherwise we wouldn't be here), but being heavyweight is not one of them. I would actively encourage authors of said library (Victor Stinner is listed as the current maintainer) to get involved in the discussion of this PEP. It is their legacy that this work is picking up from. Incidentally, I've noticed a few bug fix releases come through for IPy on PyPI in the last month so that project certainly seems alive and well. I think the PEP currently doesn't provide appropriate weight to the efforts of others in this area. FYI, here is a wiki entry I've been maintaining for a while now to this end :- http://code.google.com/p/netaddr/wiki/YetAnotherPythonIPModule
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!
yes, netaddr has sped up quite a bit. It's still slower in many cases as well. But again, who's timing?
I mention speed and timings as the PEP cites this as one of the benefits of considering the ipaddr reference implementation.
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 admirably.
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 improvement.
I'm not sure what point you're trying to make here. I didn't say it was impossible, I inferred that there are easier ways. having used code which crams both types into one object, I found it to be cludgey and complicated so I designed something different.
Let me clarify. I am +1 on the specific item in the PEP regarding the need for separate and distinct IPAddress and IPNetwork class interfaces that are not conflated into a single interface. Clay McClure made this point very eloquently. I've done a good bit of experimentation on this since it was mentioned so I am fully aware of the pros and cons of each approach. A brief look at netaddr.ip.lite confirms that on this we both agree. Where I disagree is on the need to have yet another split in the interface to support different IP versions (and a set of Factory functions to pull it all together again). Hey, another design pattern, also known as the "Factory Method" a.k.a. Virtual Constructor (or in this case a Python function).
and as a hardly partial observer, I'll add the explicit address version you can pass to the IPAddress class, but not the IPNetwork class, is, odd. it actually seems to slow down object creation (~5%) except in the case of an int arg (your default is about twice as slow).
Ah, the issue of speed and timings again. Let's concentrate on getting the interface right before we spend too much effort on optimization. I'm quite happy to do a full speed comparison of major features in both libraries but I don't think that would be a worthwhile use of time just now. Currently I'm ambivalent on whether an IP(vX)Network class constructor should accept a numerical (i.e. integer) value at all *unless* you explicit state somehow that you want the network aspect to be inferred in some specific way. It isn't a case of just choosing /32 or /128 and having this as the only option. IP (v4) classful rules are still pervasive in the real world. A general case IP library available to the whole Python community should certainly take this into account.
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 :-
collapse_address_list([IPv4Address('1.1.1.1'), IPv6Address('::1.1.1.1')]) [IPv4Network('1.1.1.1/32' <http://1.1.1.1/32%27>)]
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 :-
http://code.google.com/p/ipaddr-py/issues/detail?id=18
Compare this with netaddr's behaviour :-
cidr_merge([IPAddress('1.1.1.1'), IPAddress('::1.1.1.1')]) [IPNetwork('1.1.1.1/32' <http://1.1.1.1/32%27>), IPNetwork(':: 1.1.1.1/128' <http://1.1.1.1/128%27>)]
That's more like it.
OUCH! indeed. I'm not even sure that this is a nice corner case feature, summarizing a single list of mixed ip type objects. with an extra line or two, this can be done in ipaddr, though 'tis true that we should now raise an exception and don't (it appears to be something that was introduced recently). If this is a feature for which developers are clamoring, I'm all over it. Yours is the first email I've heard mention it.
I may be the only one raising issues but that shouldn't mean they are any less relevant. There is a whole different feel and thrust behind both interfaces each with their own merits.
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.
this basically smacks of more petty attackery from the start. so I'll reply with, "it's just you".
if you want to debate the merits of GOF strategy vs. multiple inheritance, fine. the class inheritance in ipaddr is very clean, and leaves very little code duplication. The classes are very clearly named and laid out, and in general are much easier to follow than the strategy method you've chosen for netaddr.
I realise you've done a lot of work on ipaddr and my observations are not intended as a "petty attackery" as you put it. It was merely to question whether the shift in approach from earlier incarnations of ipaddr to this is the correct path to be taking. I don't think that solely relying on "IS A" via multiple inheritance necessarily brings clarity to this code which, as stated in the PEP, is intended to be simple for other to understand and possibly use as a basis for their own extensions. More on this in future posts. If you missed it I have diagrammed the class hierarchy and internal layout of each library here for consideration :- http://code.google.com/p/netaddr/wiki/PEP3144 [SNIP]
5) The ipaddr library is also missing options for expanding various (exceedingly common) IP abbreviations.
from netaddr import IPNetwork
IPNetwork('10/8', True) IPNetwork('10.0.0.0/8')
netaddr also handles classful IP address logic, still pervasive throughout modern IP stacks :-
IPNetwork('192.168.0.1', True) IPNetwork('192.168.0.1/24')
Note that these options are disabled by default, to keep up the speed of the IPNetwork constructor up for more normal cases.
these seem like corner case features for the sake of having features, you don't even seem to put much stock in them. FWIW, I've never seen a request for something similar. I may say '10 slash 8', but I mean, '10.0.0.0/8'. I'm missing the utility here, but I'm open to reasoned arguments.
I don't see why genuine features should be automatically dismissed as "corner cases". If you need proof, here an excerpt from RFC 1918 :- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 3. Private Address Space The Internet Assigned Numbers Authority (IANA) has reserved the following three blocks of the IP address space for private internets: 10.0.0.0 - 10.255.255.255 (10/8 prefix) 172.16.0.0 - 172.31.255.255 (172.16/12 prefix) 192.168.0.0 - 192.168.255.255 (192.168/16 prefix) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ I've also had specific requests from users about this feature, one just in the last week (which only required me to point them towards the available switch argument in IPNetwork constructor to enable the required behaviour). In netaddr 0.7.x I have chosen *not* to make this expansion the default case because it provides a not insignificant construction penalty for those that are not interested in it (as you have already noted and of which I am aware). I believe strongly that this *is* an important option for a general use IP address library. [SNIP]
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.
I'm always open to serious debate, and patches/bug reports (apologies for missing your earlier issue. I'm not sure if you were aware, but ipaddr was undergoing a major re-write at the time and I never got around to following up).
I note your response to this on the ipaddr bug tracker today, thanks. [SNIP]
PS - Why does the References section in the PEP contain links to patches
already applied to the ipaddr 2.0.x reference implementation?
There's A link to A patch (singular, both times), which has already been applied. This link exists b/c, at the time I last updated the PEP, the patch hadn't been applied as it was still being reviewed.
Thanks for the clarification. [SNIP] in general, that leads
to fewer bugs like the following:
help(netaddr.IPNetwork.__init__) Help on method __init__ in module netaddr.ip:
__init__(self, addr, implicit_prefix=False) unbound netaddr.ip.IPNetwork method Constructor.
@param addr: an IPv4 or IPv6 address with optional CIDR prefix, netmask or hostmask. May be an IP address in representation (string) format, an integer or another IP object (copy construction).
@param implicit_prefix: if True, the constructor uses classful IPv4 rules to select a default prefix when one is not provided. If False it uses the length of the IP address version. (default: False).
netaddr.IPNetwork(1) Traceback (most recent call last): File "<stdin>", line 1, in <module> File "./netaddr/ip/__init__.py", line 632, in __init__ prefix, suffix = addr.split('/') AttributeError: 'int' object has no attribute 'split'
vs.
import ipaddr ipaddr.IPNetwork(1) IPv4Network('0.0.0.1/32')
Thanks for raising this on the netaddr bug tracker. I'll take a look at it. Did you have any other comments on the PEP?
Yes I do but they will be coming through in stages unfortunately as I get time to look at this further. David Moss
DrKJam wrote:
Currently I'm ambivalent on whether an IP(vX)Network class constructor should accept a numerical (i.e. integer) value at all *unless* you explicit state somehow that you want the network aspect to be inferred in some specific way. It isn't a case of just choosing /32 or /128 and having this as the only option. IP (v4) classful rules are still pervasive in the real world. A general case IP library available to the whole Python community should certainly take this into account.
Don't forget that separating the "from_int" construction behaviour out to a separate class method is an available option rather than type-based behaviour switching in the main constructor. Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia ---------------------------------------------------------------
DrKJam <drkjam <at> gmail.com> writes:
netaddr employs a simple variant of the GoF Strategy design pattern (with added Python sensibility).
It would be nice if you could avoid employing this kind of acronyms without explaining them. Not everybody drinks the design pattern kool-aid. (Google tells me that GoF seems to mean "Gang of Four", which is of course as meaningful as a hip-hop band name can be :-)) In any case, if you think netaddr's implementation strategy is better than ipaddr's, a detailed comparison would be welcome. Regards Antoine.
netaddr employs a simple variant of the GoF Strategy design pattern (with added Python sensibility).
It would be nice if you could avoid employing this kind of acronyms without explaining them. Not everybody drinks the design pattern kool-aid. (Google tells me that GoF seems to mean "Gang of Four", which is of course as meaningful as a hip-hop band name can be :-))
In any case, if you think netaddr's implementation strategy is better than ipaddr's, a detailed comparison would be welcome.
Just in case it still isn't clear "Strategy" above doesn't refer to "implementation strategy" (i.e. "way of implementing things"). Instead, "Strategy" is a specific design pattern, originally defined by one of Erich Gamma, Richard Helm, Ralph Johnson and John Vlissides. See http://en.wikipedia.org/wiki/Strategy_pattern for a detailed description. The basic idea is that you can switch algorithms at run-time, by merely replacing one object with another. To use it, you define an abstract base class with a method called "execute". You then create as many subclasses as you want, redefining "execute" to provide specific *strategies*. You create a (often global) variable pointing to one instance of the base class, and dynamically assign this variable with an instance of the appropriate strategy class. Users of the strategy don't need to know what strategy is chosen. The wikipedia article points (IMO correctly) out that the Strategy pattern is mostly useless in languages that have true function pointers, such as Python. You can still have the global variable part, but you don't need the abstract base class part at all. In the specific case of netaddr, I think David is referring to the netaddr.strategy package, which has modules called ipv4 and ipv6, both implementing functions like valid_str and str_to_arpa. Then, class IPAddress has a method reverse_dns, which is defined as def reverse_dns(self): """The reverse DNS lookup record for this IP address""" return self._module.int_to_arpa(self._value) So IPv4 addresses and IPv6 addresses share the same class, but instances have different values of _module. IPAddress.__init__ looks at the version keyword parameter if given, otherwise, it tries str_to_int first for v4, then for v6. Whether that's better or not than using subclasses, I don't know. Regards, Martin
Martin v. Löwis <martin <at> v.loewis.de> writes:
[...] Then, class IPAddress has a method reverse_dns, which is defined as
def reverse_dns(self): """The reverse DNS lookup record for this IP address""" return self._module.int_to_arpa(self._value)
So IPv4 addresses and IPv6 addresses share the same class, but instances have different values of _module.
Ok, thanks for the explanation. It looks like an inheritance-based approach would allow for easier and more traditional introspection (e.g. `isinstance(ip, IPv4Address)`). Not to mention that avoiding an indirection level can make things faster. Regards Antoine.
Antoine Pitrou <solipsis@pitrou.net> writes:
DrKJam <drkjam <at> gmail.com> writes:
netaddr employs a simple variant of the GoF Strategy design pattern (with added Python sensibility).
It would be nice if you could avoid employing this kind of acronyms without explaining them. Not everybody drinks the design pattern kool-aid.
A pity, since the entire point of Design Patterns is to give us a vocabulary of terms to use that enable these concepts to be communicated *without* continually re-defining them. To that extent, then, they fail their purpose. -- \ “Our wines leave you nothing to hope for.” —restaurant menu, | `\ Switzerland | _o__) | Ben Finney
DrKJam <drkjam <at> gmail.com> writes:
netaddr employs a simple variant of the GoF Strategy design pattern (with added Python sensibility).
It would be nice if you could avoid employing this kind of acronyms without explaining them. Not everybody drinks the design pattern kool-aid.
A pity, since the entire point of Design Patterns is to give us a vocabulary of terms to use that enable these concepts to be communicated *without* continually re-defining them. To that extent, then, they fail their purpose.
I think it's too early to tell. It may be that they have not yet achieved their purpose - just let's wait fifty more years (and I'm only half-joking). Regards, Martin
Martin> I think it's too early to tell. It may be that they have not yet Martin> achieved their purpose - just let's wait fifty more years (and Martin> I'm only half-joking). So what you're really saying is we only have to wait 25 years... Skip
I've started a very basic (work in progress) entry on the netaddr wiki to track various aspects of this discussion that might not be in a format suitable for publishing to the list or are too lengthy. It will also allow my ascii art diagrams to render correctly ;-) http://code.google.com/p/netaddr/wiki/PEP3144 I will be updating it as free time become available to me over the coming days. Feel free to make comments on the wiki page itself if you want me to make any changes. Duncan McGreggor should be able to make changes if I am not available for whatever reason :- If anyone has suggestions for a better place to put this, please shout (but not too loudly please Peter M. ;-) Thanks, Dave M. PS - Can't wait for Google Wave which would make this kind of thing so much easier ;-)
On Wed, Aug 26, 2009 at 4:48 PM, DrKJam<drkjam@gmail.com> wrote:
I've started a very basic (work in progress) entry on the netaddr wiki to track various aspects of this discussion that might not be in a format suitable for publishing to the list or are too lengthy. It will also allow my ascii art diagrams to render correctly ;-)
http://code.google.com/p/netaddr/wiki/PEP3144
I will be updating it as free time become available to me over the coming days. Feel free to make comments on the wiki page itself if you want me to make any changes. Duncan McGreggor should be able to make changes if I am not available for whatever reason :-
If anyone has suggestions for a better place to put this, please shout (but not too loudly please Peter M. ;-)
you know, Dave, I'm actually pretty tired of your snide remarks. Your passive aggressive emails, your inability to remember when or be honest about why you unsubbed me from the netaddr list, etc. are not the actions of someone seeking serious debate about the best possible library for python. To answer your 'where' question, http://www.python.org/dev/peps/pep-0001/ is pretty clear on where peps should be submitted: specifically, "We try to build consensus around a PEP, but if that's not possible, you can always submit a competing PEP." I'm not personally looking forward waiting around for more of your free time to become available before you can get to updating your wiki (which, btw, seems to be both out of date and otherwise incorrect wrt ipaddr and shockingly under-representative of the complexity of netaddr). Hopefully the code you've written is currently in a more complete state than the wiki and can be judged as it is. Cheers, /peter
Thanks,
Dave M.
PS - Can't wait for Google Wave which would make this kind of thing so much easier ;-)
_______________________________________________ Python-Dev mailing list Python-Dev@python.org http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/python-dev%40hda3.com
Peter, I would like to apologise if I have caused you any offense. Please can we put the animosity behind us and stick to pulling together the best IP library possible as part of this PEP? Regards, Dave M.
On Thu, Aug 27, 2009 at 10:24 AM, David Moss<drkjam@gmail.com> wrote:
Peter,
I would like to apologise if I have caused you any offense.
Thanks. Accepted.
Please can we put the animosity behind us and stick to pulling together the best IP library possible as part of this PEP?
pep-3144 should hopefully soon be updated on python.org/dev/peps with this past week's suggestions (including a discussion on the ipaddr class design). The updated ipaddr reference code should also still be available for 'svn co' at https://ipaddr-py.googlecode.com/svn/branches/2.0.x Cheers, /peter
Regards,
Dave M.
On Thu, Aug 27, 2009 at 10:37 AM, Peter Moody<peter@hda3.com> wrote:
On Thu, Aug 27, 2009 at 10:24 AM, David Moss<drkjam@gmail.com> wrote:
Peter,
I would like to apologise if I have caused you any offense.
Thanks. Accepted.
Please can we put the animosity behind us and stick to pulling together the best IP library possible as part of this PEP?
pep-3144 should hopefully soon be updated on python.org/dev/peps with this past week's suggestions (including a discussion on the ipaddr class design). The updated ipaddr reference code should also still be available for 'svn co' at https://ipaddr-py.googlecode.com/svn/branches/2.0.x
er, make that http://ipaddr-py.googlecode.com/svn/branches/2.0.x https seems to ask for a password.
Cheers, /peter
Regards,
Dave M.
I've posted several of issues to the ipaddr bug tracker for consideration. They shouldn't be major discussion topics so I'll leave them off the list. The following are a few feature requests that might possibly require further discussion here. If they are no-brainers that don't require any further mulling over, can we have a few votes -1/+1 to get a feel for the importance and I'llI convert them into tickets. 1) Additional is_<network_class> boolean properties. IPv6Address.is_ipv4_compat IPv6Network.is_ipv4_compat Returns True if this address/network is IPv4-compatible IPv6 e.g. ::192.0.2.0 or ::192.0.2.0/124, False otherwise. IPv6Address.is_ipv4_mapped IPv6Network.is_ipv4_mapped Returns True if this address/network is IPv4-compatible IPv6 e.g. ::ffff:192.0.2.0 or ::ffff:192.0.2.0/124, False otherwise. IPvXAddress.is_reserved IPvXNetwork.is_reserved Possible list of IPv4 networks and ranges to be used for this purpose :- # IANA Reserved but subject to allocation 39.0.0.0/8 128.0.0.0/16 191.255.0.0/16 192.0.0.0/24 223.255.255.0/24 # Reserved for Future Use 240.0.0.0/4 # Reserved multicast 234.0.0.0 - 238.255.255.255 225.0.0.0 - 231.255.255.255 Possible list of IPv6 networks to be used for this purpose :- FF00::/12 ::/8 0100::/8 0200::/7 0400::/6 0800::/5 1000::/4 4000::/3 6000::/3 8000::/3 A000::/3 C000::/3 E000::/4 F000::/5 F800::/6 FE00::/9 IPvXAddress.is_unicast IPvXNetwork.is_unicast True if addresses or networks are within unicast ranges. 2) An IPvXRange class (representing an arbitrary start and end IP address). This is in addition to the existing summarize_address_range() function. There are use cases were an actual object representing an arbitrary range rather than a basic tuple containing two IPvXAddress objects or a list of IPvXNetwork objects is just simple to handle, more appropriate and less hassle overall. Willing to expand on the interface for this. 3) Support for IPv4-mapped/compatible IPv6 conversion functions. It would be handy to have methods to convert backwards and forwards between actual IPv4 addresses and networks to their IPv6 mapped or compatible counterparts. Basic examples :- IPv4 -> IPv6
IPv6Address('::ffff:192.0.2.0').ipv4() IPv4Address('192.0.2.0')
IPv6Address('::192.0.2.0').ipv4() IPv4Address('192.0.2.0')
IPv4Address('192.0.2.0').ipv6() IPv6Address(::ffff:192.0.2.0') Prefer IPv4-compatible as the default (RFC
IPv4 -> IPv6 4291)
IPv4Address('192.0.2.0').ipv6(ipv4_mapped=True) IPv6Address('::192.0.2.0')
By the same token we should provide the same functionality for IP network classes (with the necessary CIDR prefix conversions) :-
IPv6Network('::ffff:192.0.2.0/120').ipv4() IPv4Network('192.0.2.0/24')
IPv4Network('192.0.2.0/24').ipv6() IPv6Network('::ffff:192.0.2.0/120')
IPv4Network('192.0.2.0/24').ipv6(ipv4_mapped=True) IPv6Network('::192.0.2.0/120')
If address ranges overflow boundaries the necessary exceptions can be thrown. 4) IP set based classes. This is a big topic, so I'll save it for a subsequent post. What are the general feelings about having something like this in ipaddr? It might be deemed a little heavyweight but it is a really sweet option for the power user. Combined with the new speed of collapse_address_list() this could be handy and fast. That's all for now, Dave M. 2009/8/27 Peter Moody <peter@hda3.com>
On Thu, Aug 27, 2009 at 10:37 AM, Peter Moody<peter@hda3.com> wrote:
On Thu, Aug 27, 2009 at 10:24 AM, David Moss<drkjam@gmail.com> wrote:
Peter,
I would like to apologise if I have caused you any offense.
Thanks. Accepted.
Please can we put the animosity behind us and stick to pulling together the best IP library possible as part of this PEP?
pep-3144 should hopefully soon be updated on python.org/dev/peps with this past week's suggestions (including a discussion on the ipaddr class design). The updated ipaddr reference code should also still be available for 'svn co' at https://ipaddr-py.googlecode.com/svn/branches/2.0.x
er, make that http://ipaddr-py.googlecode.com/svn/branches/2.0.x
https seems to ask for a password.
Cheers, /peter
Regards,
Dave M.
IPv6Address.is_ipv4_compat IPv6Network.is_ipv4_compat
Returns True if this address/network is IPv4-compatible IPv6 e.g. ::192.0.2.0 or ::192.0.2.0/124 <http://192.0.2.0/124>, False otherwise.
-1. These addresses are deprecated.
IPv6Address.is_ipv4_mapped IPv6Network.is_ipv4_mapped
Returns True if this address/network is IPv4-compatible IPv6 e.g. ::ffff:192.0.2.0 or ::ffff:192.0.2.0/124 <http://192.0.2.0/124>, False otherwise.
Perhaps there could be a v4_mapped function, that returned either None or a V4 address?
IPvXAddress.is_reserved IPvXNetwork.is_reserved
Possible list of IPv4 networks and ranges to be used for this purpose :-
# IANA Reserved but subject to allocation 39.0.0.0/8 <http://39.0.0.0/8>
-1. These are merely unallocated.
128.0.0.0/16 <http://128.0.0.0/16>
-1. RFC 3330 says they are subject to allocation.
191.255.0.0/16 <http://191.255.0.0/16>
-1. It's allocated to LACNIC, for further allocation.
192.0.0.0/24 <http://192.0.0.0/24>
-1. It's allocated to ARIN; RFC 3330 says it's free for allocation.
223.255.255.0/24 <http://223.255.255.0/24>
-1. Not sure what the status is here, but RFC 3330 also lists it as available for allocation; IANA lists 223.0.0.0/8 as UNALLOCATED.
# Reserved for Future Use 240.0.0.0/4 <http://240.0.0.0/4>
+1.
# Reserved multicast 234.0.0.0 - 238.255.255.255 225.0.0.0 - 231.255.255.255
-0. What makes them different from, say, 224.0.0.0/8?
Possible list of IPv6 networks to be used for this purpose :-
FF00::/12
-1. These are multicast addresses, some in use.
::/8 0100::/8 0200::/7 0400::/6 0800::/5 1000::/4 4000::/3 6000::/3 8000::/3 A000::/3 C000::/3 E000::/4 F000::/5 F800::/6 FE00::/9
+1.
IPvXAddress.is_unicast IPvXNetwork.is_unicast
True if addresses or networks are within unicast ranges.
-0. What about anycast addresses?
2) An IPvXRange class (representing an arbitrary start and end IP address). This is in addition to the existing summarize_address_range() function.
There are use cases were an actual object representing an arbitrary range rather than a basic tuple containing two IPvXAddress objects or a list of IPvXNetwork objects is just simple to handle, more appropriate and less hassle overall. Willing to expand on the interface for this.
-0. What's use case where a tuple of two addresses wouldn't be just as good?
Basic examples :-
IPv4 -> IPv6
IPv6Address('::ffff:192.0.2.0').ipv4() IPv4Address('192.0.2.0')
IPv6Address('::192.0.2.0').ipv4() IPv4Address('192.0.2.0')
-1 in this form. See above for compatible and mapped addresses. I could imaging a method trailing_ipv4, which would give an IPv4 address when all bits between 64 and 95 are 0; this would also cover cases where people put the IPv4 address into the IPv6 address using a regular prefix. Of course, this is guess-work, so the method name has to make it clear that it is guessing.
IPv4 -> IPv6
IPv4Address('192.0.2.0').ipv6() IPv6Address(::ffff:192.0.2.0') Prefer IPv4-compatible as the default (RFC 4291)
-1. These are deprecated.
IPv4Address('192.0.2.0').ipv6(ipv4_mapped=True) IPv6Address('::192.0.2.0')
-0. Call it ipv4_mapped(). If there is to be an ipv6 method, it should take an IPv6Network, to allow constructing things like 2001:888:2000:d::82.94.164.162.
4) IP set based classes.
This is a big topic, so I'll save it for a subsequent post. What are the general feelings about having something like this in ipaddr? It might be deemed a little heavyweight but it is a really sweet option for the power user. Combined with the new speed of collapse_address_list() this could be handy and fast.
So when talking about it, please provide use cases. Regards, Martin
skip@pobox.com wrote:
Martin> I think it's too early to tell. It may be that they have not yet Martin> achieved their purpose - just let's wait fifty more years (and Martin> I'm only half-joking).
So what you're really saying is we only have to wait 25 years...
:) Martin has a really good point though - software development is still pretty immature as a discipline, being around for mere decades as opposed to the centuries (or more) that other activities like mathematics, physics or construction have behind them. Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia ---------------------------------------------------------------
Ben Finney writes:
A pity, since the entire point of Design Patterns is to give us a vocabulary of terms to use that enable these concepts to be communicated *without* continually re-defining them. To that extent, then, they fail their purpose.
Of course not! There will always be children ... I hope. The point of Design Patterns is to give a vocabulary that can be used in an "in group" context without any explanation at all, and in the stylized form This implementation follows the "Strategy" design pattern of Ralf, Joel, Yen-shih, and Gundarmambanagoong, which is ... which educates the young and allows the cognoscenti to daydream for a minute.
Ben Finney wrote:
Antoine Pitrou <solipsis@pitrou.net> writes:
DrKJam <drkjam <at> gmail.com> writes:
netaddr employs a simple variant of the GoF Strategy design pattern (with added Python sensibility).
It would be nice if you could avoid employing this kind of acronyms without explaining them. Not everybody drinks the design pattern kool-aid.
A pity, since the entire point of Design Patterns is to give us a vocabulary of terms to use that enable these concepts to be communicated *without* continually re-defining them. To that extent, then, they fail their purpose.
My experience with them the named design patterns is that: 1. An awful lot of them seem to be just about working around some of the limitations of static typing, a lack of functions as first class objects, or are in some other way a lot less useful outside a C++/Java environment. 2. Others are used intuitively by a lot of developers that have never even heard of any of the GoF authors or the Design Patterns book (the Adapter pattern being the most common example that occurs to me). I still think most people (even those that primarily work in dynamic languages) can learn something by reading it, but following their examples too slavishly creates evils of its own (especially when attempting to apply patterns that don't really suit the language being used). When the inappropriate use of named patterns runs counter to the accepted idioms of a language is when I see terms like the "design pattern kool-aid" mentioned above getting thrown around :) Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia ---------------------------------------------------------------
Antoine Pitrou wrote:
DrKJam <drkjam <at> gmail.com> writes:
netaddr employs a simple variant of the GoF Strategy design pattern (with
added Python sensibility).
It would be nice if you could avoid employing this kind of acronyms without explaining them. Not everybody drinks the design pattern kool-aid. (Google tells me that GoF seems to mean "Gang of Four", which is of course as meaningful as a hip-hop band name can be :-))
Really? Discussing the GoF design patterns by name seems to be prevalent amongst the programmers I know (yourself excluded of course...). Michael
In any case, if you think netaddr's implementation strategy is better than ipaddr's, a detailed comparison would be welcome.
Regards
Antoine.
_______________________________________________ Python-Dev mailing list Python-Dev@python.org http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/fuzzyman%40voidspace.org.u...
-- http://www.ironpythoninaction.com/ http://www.voidspace.org.uk/blog
Michael Foord <fuzzyman <at> voidspace.org.uk> writes:
Really? Discussing the GoF design patterns by name seems to be prevalent amongst the programmers I know (yourself excluded of course...).
Ah? I still haven't understood what "Gang of Four" is supposed to be, however. Is it a design pattern? Besides, saying "I use the strategy design pattern" doesn't tell a lot, while an ad hoc description is much more informational (witness Martin's explanation for example). It's like those frameworks who have a class simply named "Factory" ;) Regards Antoine.
Antoine Pitrou wrote:
Michael Foord <fuzzyman <at> voidspace.org.uk> writes:
Really? Discussing the GoF design patterns by name seems to be prevalent amongst the programmers I know (yourself excluded of course...).
Ah? I still haven't understood what "Gang of Four" is supposed to be, however. Is it a design pattern?
The gang of four are the four folk who wrote the classic design patterns book: http://en.wikipedia.org/wiki/Design_Patterns_%28book%29 Erich Gamma, Richard Helm, Ralph Johnson and John Vlissides.
Besides, saying "I use the strategy design pattern" doesn't tell a lot, while an ad hoc description is much more informational (witness Martin's explanation for example).
It's like those frameworks who have a class simply named "Factory" ;)
Well, depending on the circumstances it can convey some to no information. :-) Michael
Regards
Antoine.
_______________________________________________ Python-Dev mailing list Python-Dev@python.org http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/fuzzyman%40voidspace.org.u...
-- http://www.ironpythoninaction.com/ http://www.voidspace.org.uk/blog
http://ipaddr-py.googlecode.com/svn/branches/2.0.x/ipaddr.py
_compat_has_real_bytes = bytes != str
Wouldn't it be nicer "bytes is not str"? Oleg. -- Oleg Broytmann http://phd.pp.ru/ phd@phd.pp.ru Programmers don't die, they just GOSUB without RETURN.
On Fri, Aug 21, 2009 at 4:00 AM, Oleg Broytmann<phd@phd.pp.ru> wrote:
http://ipaddr-py.googlecode.com/svn/branches/2.0.x/ipaddr.py
_compat_has_real_bytes = bytes != str
Wouldn't it be nicer "bytes is not str"?
it is. fixing this. Cheers, /peter
Oleg. -- Oleg Broytmann http://phd.pp.ru/ phd@phd.pp.ru Programmers don't die, they just GOSUB without RETURN. _______________________________________________ Python-Dev mailing list Python-Dev@python.org http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/python-dev%40hda3.com
Howdy folks, the reference code has been updated per your comments; specifically, there's no more IP/IPv4/IPv6 factory functions, it's all IPAddress() and IPNetwork constructors. I've submitted a patch to the PEP with updated examples and a lengthy description of the class inheritance and the benefits from that design choice. hopefully that should go live soon. If there are any more suggestions on the PEP or the code, please let me know. Cheers, /peter On Tue, Aug 18, 2009 at 1:00 PM, Peter Moody<peter@hda3.com> wrote:
Howdy folks,
I have a first draft of a PEP for including an IP address manipulation library in the python stdlib. It seems like there are a lot of really smart folks with some, ahem, strong ideas about what an IP address module should and shouldn't be so I wanted to solicit your input on this pep.
the pep can be found here:
http://www.python.org/dev/peps/pep-3144/
the code can be found here:
http://ipaddr-py.googlecode.com/svn/branches/2.0.x/
Please let me know if you have any comments (some already coming :)
Cheers, /peter
Peter Moody wrote:
If there are any more suggestions on the PEP or the code, please let me know.
I noticed the new paragraphs on the IPv4 vs IPv6 types not being comparable - is there a canonical ordering for mixed address lists defined anywhere (e.g. an RFC)? If there is, then it should be possible to implement that on BaseIP and BaseNet so that comparisons work as canonically defined. If there isn't, then that should be mentioned in the PEP as the reason why the PEP deliberately isn't trying to invent a convention. Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia ---------------------------------------------------------------
On Fri, Aug 28, 2009 at 2:31 AM, Nick Coghlan<ncoghlan@gmail.com> wrote:
Peter Moody wrote:
If there are any more suggestions on the PEP or the code, please let me know.
I noticed the new paragraphs on the IPv4 vs IPv6 types not being comparable - is there a canonical ordering for mixed address lists defined anywhere (e.g. an RFC)?
If there is, then it should be possible to implement that on BaseIP and BaseNet so that comparisons work as canonically defined. If there isn't, then that should be mentioned in the PEP as the reason why the PEP deliberately isn't trying to invent a convention.
updated the pep with more information about this. working through changes/issues brought up by David and Martin. Cheers, /peter
Cheers, Nick.
-- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia --------------------------------------------------------------- _______________________________________________ Python-Dev mailing list Python-Dev@python.org http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/python-dev%40hda3.com
Howdy, So I've made most of the suggested changes here and put up a release of ipaddr. Do folks here consider this pep is final (enough) for submission or is there more work to be done? Cheers, /peter On Thu, Aug 27, 2009 at 6:52 AM, Peter Moody<peter@hda3.com> wrote:
Howdy folks,
the reference code has been updated per your comments; specifically, there's no more IP/IPv4/IPv6 factory functions, it's all IPAddress() and IPNetwork constructors.
I've submitted a patch to the PEP with updated examples and a lengthy description of the class inheritance and the benefits from that design choice. hopefully that should go live soon.
If there are any more suggestions on the PEP or the code, please let me know.
Cheers, /peter
On Tue, Aug 18, 2009 at 1:00 PM, Peter Moody<peter@hda3.com> wrote:
Howdy folks,
I have a first draft of a PEP for including an IP address manipulation library in the python stdlib. It seems like there are a lot of really smart folks with some, ahem, strong ideas about what an IP address module should and shouldn't be so I wanted to solicit your input on this pep.
the pep can be found here:
http://www.python.org/dev/peps/pep-3144/
the code can be found here:
http://ipaddr-py.googlecode.com/svn/branches/2.0.x/
Please let me know if you have any comments (some already coming :)
Cheers, /peter
participants (22)
-
"Martin v. Löwis"
-
Alexey S
-
Antoine Pitrou
-
Ben Finney
-
Case Vanhorsen
-
David Moss
-
DrKJam
-
Eric Smith
-
Fred Drake
-
Glyph Lefkowitz
-
Guido van Rossum
-
Jake McGuire
-
Jeroen Ruigrok van der Werven
-
Joel Bender
-
Michael Foord
-
Nick Coghlan
-
Oleg Broytmann
-
Peter Moody
-
R. David Murray
-
skip@pobox.com
-
Stephen J. Turnbull
-
Tino Wildenhain