Folks, Guido, I believe PEP 3144 is ready for your review. When you get a chance, can you take a look/make a pronouncement? Cheers, /peter
What's the opinion of the other interested party or parties? I don't want a repeat of the events last time, where we had to pull it at the last time because there hadn't been enough discussion. On Mon, Sep 14, 2009 at 9:44 AM, Peter Moody <peter@hda3.com> wrote:
Folks, Guido,
I believe PEP 3144 is ready for your review. When you get a chance, can you take a look/make a pronouncement?
Cheers, /peter
-- --Guido van Rossum (home page: http://www.python.org/~guido/)
On Mon, Sep 14, 2009 at 9:54 AM, Guido van Rossum <guido@python.org> wrote:
What's the opinion of the other interested party or parties? I don't want a repeat of the events last time, where we had to pull it at the last time because there hadn't been enough discussion.
How many other people are using this library? I think it's hard to give really useful feedback on an API without using it for some non-trivial task, but maybe other people don't have this problem. -jake
On Tue, Sep 15, 2009 at 10:16 AM, Jake McGuire <mcguire@google.com> wrote:
On Mon, Sep 14, 2009 at 9:54 AM, Guido van Rossum <guido@python.org> wrote:
What's the opinion of the other interested party or parties? I don't want a repeat of the events last time, where we had to pull it at the last time because there hadn't been enough discussion.
How many other people are using this library? I think it's hard to give really useful feedback on an API without using it for some non-trivial task, but maybe other people don't have this problem. -jake
188 (check that, 190) people have downloaded the 2.0 release in the last week (numbers publicly available from the code.google.com). I can't tell you how many (if any) have downloaded it via svn. Cheers, /peter
On Tue, Sep 15, 2009 at 10:36 AM, Peter Moody <peter@hda3.com> wrote:
On Tue, Sep 15, 2009 at 10:16 AM, Jake McGuire <mcguire@google.com> wrote:
On Mon, Sep 14, 2009 at 9:54 AM, Guido van Rossum <guido@python.org> wrote:
What's the opinion of the other interested party or parties? I don't want a repeat of the events last time, where we had to pull it at the last time because there hadn't been enough discussion.
How many other people are using this library? I think it's hard to give really useful feedback on an API without using it for some non-trivial task, but maybe other people don't have this problem. -jake
188 (check that, 190) people have downloaded the 2.0 release in the last week (numbers publicly available from the code.google.com). I can't tell you how many (if any) have downloaded it via svn.
Downloading and using are not the same thing. -jake
On Tue, Sep 15, 2009 at 11:33 AM, Jake McGuire <mcguire@google.com> wrote:
On Tue, Sep 15, 2009 at 10:36 AM, Peter Moody <peter@hda3.com> wrote:
On Tue, Sep 15, 2009 at 10:16 AM, Jake McGuire <mcguire@google.com> wrote:
On Mon, Sep 14, 2009 at 9:54 AM, Guido van Rossum <guido@python.org> wrote:
What's the opinion of the other interested party or parties? I don't want a repeat of the events last time, where we had to pull it at the last time because there hadn't been enough discussion.
How many other people are using this library? I think it's hard to give really useful feedback on an API without using it for some non-trivial task, but maybe other people don't have this problem. -jake
188 (check that, 190) people have downloaded the 2.0 release in the last week (numbers publicly available from the code.google.com). I can't tell you how many (if any) have downloaded it via svn.
Downloading and using are not the same thing.
Correct, but there is a strong positive correlation between the two. If you have a better method for determining what you would consider an appropriate level of usage, I'm all ears.
-jake
On Tue, Sep 15, 2009 at 11:36 AM, Peter Moody <peter@hda3.com> wrote:
On Tue, Sep 15, 2009 at 11:33 AM, Jake McGuire <mcguire@google.com> wrote:
On Tue, Sep 15, 2009 at 10:36 AM, Peter Moody <peter@hda3.com> wrote:
On Tue, Sep 15, 2009 at 10:16 AM, Jake McGuire <mcguire@google.com>
wrote:
On Mon, Sep 14, 2009 at 9:54 AM, Guido van Rossum <guido@python.org> wrote:
What's the opinion of the other interested party or parties? I don't want a repeat of the events last time, where we had to pull it at the last time because there hadn't been enough discussion.
How many other people are using this library? I think it's hard to give really useful feedback on an API without using it for some non-trivial task, but maybe other people don't have this problem. -jake
188 (check that, 190) people have downloaded the 2.0 release in the last week (numbers publicly available from the code.google.com). I can't tell you how many (if any) have downloaded it via svn.
Downloading and using are not the same thing.
Correct, but there is a strong positive correlation between the two. If you have a better method for determining what you would consider an appropriate level of usage, I'm all ears.
Put something on the project page (or download page if possible) saying "ipaddr is being considered for inclusion in the Python standard library. We want to make sure it meets your needs, but we need you to tell us. If you use ipaddr and like it, please let us know on ip-addr-dev." I dunno, maybe it's too much work. But no one else seems to have an opinion strong enough to share, at least not at this point. -jake
On Tue, Sep 15, 2009 at 11:44 AM, Jake McGuire <mcguire@google.com> wrote:
On Tue, Sep 15, 2009 at 11:36 AM, Peter Moody <peter@hda3.com> wrote:
On Tue, Sep 15, 2009 at 10:36 AM, Peter Moody <peter@hda3.com> wrote:
On Tue, Sep 15, 2009 at 10:16 AM, Jake McGuire <mcguire@google.com>
wrote:
On Mon, Sep 14, 2009 at 9:54 AM, Guido van Rossum <guido@python.org> wrote:
What's the opinion of the other interested party or parties? I don't want a repeat of the events last time, where we had to pull it at
On Tue, Sep 15, 2009 at 11:33 AM, Jake McGuire <mcguire@google.com> wrote: the
last time because there hadn't been enough discussion.
How many other people are using this library? I think it's hard to give really useful feedback on an API without using it for some non-trivial task, but maybe other people don't have this problem. -jake
188 (check that, 190) people have downloaded the 2.0 release in the last week (numbers publicly available from the code.google.com). I can't tell you how many (if any) have downloaded it via svn.
Downloading and using are not the same thing.
Correct, but there is a strong positive correlation between the two. If you have a better method for determining what you would consider an appropriate level of usage, I'm all ears.
Put something on the project page (or download page if possible) saying "ipaddr is being considered for inclusion in the Python standard library. We want to make sure it meets your needs, but we need you to tell us. If you use ipaddr and like it, please let us know on ip-addr-dev."
I dunno, maybe it's too much work. But no one else seems to have an opinion strong enough to share, at least not at this point.
To clarify: there will always be some group of people happy to tell you that whatever you made is crap and that it should have been done differently. There may be many more people out there who think that what you did is great. But those people probably don't read python-dev so their voices don't get heard when it comes to deciding what to do with PEP 3144. The easiest way to get their voices heard is to ask them to speak up, and the one place you know they visited was the ipaddr page on code.google.com, so you may as well ask them there. -jake
Peter Moody wrote:
On Tue, Sep 15, 2009 at 11:33 AM, Jake McGuire <mcguire@google.com> wrote:
Downloading and using are not the same thing.
Correct, but there is a strong positive correlation between the two. If you have a better method for determining what you would consider an appropriate level of usage, I'm all ears.
You sneak in a bit of code that sends a message to home base "In use from <IPaddress>";-) Kidding aside, there are usage reports, but those tend to be lower if the code satifies than if not. I think 200 indicates fair interest. Let us hope there is more feedback, pro and con. tjr
188 (check that, 190) people have downloaded the 2.0 release in the last week (numbers publicly available from the code.google.com). I can't tell you how many (if any) have downloaded it via svn.
Downloading and using are not the same thing.
Correct, but there is a strong positive correlation between the two. If you have a better method for determining what you would consider an appropriate level of usage, I'm all ears.
A good way of determining the level of usage would be pointing to open source projects that are popular in the python community and which incorporate your module. Cheers, Daniel -- Psss, psss, put it down! - http://www.cafepress.com/putitdown
On Tue, Sep 15, 2009 at 1:34 PM, Daniel Fetchinson <fetchinson@googlemail.com> wrote:
188 (check that, 190) people have downloaded the 2.0 release in the last week (numbers publicly available from the code.google.com). I can't tell you how many (if any) have downloaded it via svn.
Downloading and using are not the same thing.
Correct, but there is a strong positive correlation between the two. If you have a better method for determining what you would consider an appropriate level of usage, I'm all ears.
A good way of determining the level of usage would be pointing to open source projects that are popular in the python community and which incorporate your module.
well, the 2.0 release is still new. codesearch.google.com shows some projects using the 1.x release; hopefully some of those 200 downloaders will put up some publicly indexable python code at some point.
Cheers, Daniel
-- Psss, psss, put it down! - http://www.cafepress.com/putitdown _______________________________________________ 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
188 (check that, 190) people have downloaded the 2.0 release in the last week (numbers publicly available from the code.google.com). I can't tell you how many (if any) have downloaded it via svn.
Downloading and using are not the same thing.
Correct, but there is a strong positive correlation between the two. If you have a better method for determining what you would consider an appropriate level of usage, I'm all ears.
A good way of determining the level of usage would be pointing to open source projects that are popular in the python community and which incorporate your module.
well, the 2.0 release is still new. codesearch.google.com shows some projects using the 1.x release; hopefully some of those 200 downloaders will put up some publicly indexable python code at some point.
I think one first needs to wait until this happens, I meana large user base is formed, before a meaningful discussion can be done on whether to include it in the stdlib or not. The long and largely academic thread here I think illustrates this point. Without a large user base it's up to anybody's gut feelings what is 'right' and what 'feels wrong'. Cheers, Daniel -- Psss, psss, put it down! - http://www.cafepress.com/putitdown
On Thursday, September 17, 2009, Daniel Fetchinson <fetchinson@googlemail.com> wrote:
188 (check that, 190) people have downloaded the 2.0 release in the last week (numbers publicly available from the http://code.google.com). I can't tell you how many (if any) have downloaded it via svn.
Downloading and using are not the same thing.
Correct, but there is a strong positive correlation between the two. If you have a better method for determining what you would consider an appropriate level of usage, I'm all ears.
A good way of determining the level of usage would be pointing to open source projects that are popular in the python community and which incorporate your module.
well, the 2.0 release is still new. http://codesearch.google.com shows some projects using the 1.x release; hopefully some of those 200 downloaders will put up some publicly indexable python code at some point.
I think one first needs to wait until this happens, I meana large user base is formed, before a meaningful discussion can be done on whether to include it in the stdlib or not. The long and largely academic thread here I think illustrates this point. Without a large user base it's up to anybody's gut feelings what is 'right' and what 'feels wrong'.
+1000 -jake
On Thu, Sep 17, 2009 at 11:10 AM, Daniel Fetchinson <fetchinson@googlemail.com> wrote:
188 (check that, 190) people have downloaded the 2.0 release in the last week (numbers publicly available from the code.google.com). I can't tell you how many (if any) have downloaded it via svn.
Downloading and using are not the same thing.
Correct, but there is a strong positive correlation between the two. If you have a better method for determining what you would consider an appropriate level of usage, I'm all ears.
A good way of determining the level of usage would be pointing to open source projects that are popular in the python community and which incorporate your module.
well, the 2.0 release is still new. codesearch.google.com shows some projects using the 1.x release; hopefully some of those 200 downloaders will put up some publicly indexable python code at some point.
I think one first needs to wait until this happens, I meana large user base is formed, before a meaningful discussion can be done on whether to include it in the stdlib or not. The long and largely academic thread here I think illustrates this point. Without a large user base it's up to anybody's gut feelings what is 'right' and what 'feels wrong'.
I like the sound of this. I'm going to continue to work on the PEP and the reference implementation, but as Martin said earlier, there's no reason to hurry. any discussion on ipaddr and/or PEP 3144 can continue on ipaddr-py-dev@googlegroups.com in the meantime (past spam unfortunately means that you have to subscribe in order to post, apologies, but all are welcome). Hopefully, the continued work will help iron any remaining confusion of the API. Cheers, /peter
Cheers, Daniel
-- Psss, psss, put it down! - http://www.cafepress.com/putitdown _______________________________________________ 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
What's the opinion of the other interested party or parties? I don't want a repeat of the events last time, where we had to pull it at the last time because there hadn't been enough discussion.
I'm slightly interested, but didn't have the time to review the PEP at all yet. I may be able to do so before the end of the year, but can't promise that. In any case, I don't see a reason to hurry - if the PEP is adopted two or three months before the release of 2.7, it will still be in time, IMO. Regards, Martin
I believe PEP 3144 is ready for your review. When you get a chance, can you take a look/make a pronouncement?
In my experience it is common to leave out the masked octets when referring to an IPv4 network (the octets are assumed to be zero), so I don't agree with this behaviour from the reference implementation: >>> ipaddr.IPv4Network('10/8') IPv4Network('0.0.0.10/8') >>> ipaddr.IPv4Network('192.168/16') Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/usr/src/py/ipaddr/ipaddr.py", line 1246, in __init__ raise IPv4IpValidationError(addr[0]) ipaddr.IPv4IpValidationError: '192.168' is not a valid IPv4 address I also couldn't see an easy way to get from a network address to the containing network. For example: >>> ipaddr.IPv4Network('192.168.1.1/16') IPv4Network('192.168.1.1/16') This is close: >>> ipaddr.IPv4Network('192.168.1.1/16').network IPv4Address('192.168.0.0') What I want is a method that returns: IPv4Network('192.168.0.0/16') I appreciate these requests are somewhat contradictory (one calls for masked octets to be insignificant, the other calls for them to be significant), but they are both valid use cases in my experience. Apologies if these have already been covered in prior discussion - I've tried to keep up, but I haven't been able to give it the attention it deserves. I also note that many methods in the reference implementation are not discussed in the PEP. While I don't consider this a problem for the PEP, anyone reviewing the module for inclusion in the standard lib needs to consider them. -- Andrew McNamara, Senior Developer, Object Craft http://www.object-craft.com.au/
On Mon, Sep 14, 2009 at 7:11 PM, Andrew McNamara <andrewm@object-craft.com.au> wrote:
I believe PEP 3144 is ready for your review. When you get a chance, can you take a look/make a pronouncement?
In my experience it is common to leave out the masked octets when referring to an IPv4 network (the octets are assumed to be zero), so I don't agree with this behaviour from the reference implementation:
huh, this appears to be a bug. filing an issue and I'll have this fixed before anything is submitted (http://code.google.com/p/ipaddr-py/issues/detail?id=35)
>>> ipaddr.IPv4Network('10/8') IPv4Network('0.0.0.10/8') >>> ipaddr.IPv4Network('192.168/16') Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/usr/src/py/ipaddr/ipaddr.py", line 1246, in __init__ raise IPv4IpValidationError(addr[0]) ipaddr.IPv4IpValidationError: '192.168' is not a valid IPv4 address
I also couldn't see an easy way to get from a network address to the containing network. For example:
>>> ipaddr.IPv4Network('192.168.1.1/16') IPv4Network('192.168.1.1/16')
This is close:
>>> ipaddr.IPv4Network('192.168.1.1/16').network IPv4Address('192.168.0.0')
What I want is a method that returns:
IPv4Network('192.168.0.0/16')
I can see about adding this. you can currently do:
a = ipaddr.IPv4Network('192.168.1.1/16') '%s/%s' % (a.network, a.prefixlen) 192.168.0.0/16
(I do something very similar to this in address_exclude)
I appreciate these requests are somewhat contradictory (one calls for masked octets to be insignificant, the other calls for them to be significant), but they are both valid use cases in my experience.
Apologies if these have already been covered in prior discussion - I've tried to keep up, but I haven't been able to give it the attention it deserves.
no need to apologize, all comments welcome.
I also note that many methods in the reference implementation are not discussed in the PEP. While I don't consider this a problem for the PEP, anyone reviewing the module for inclusion in the standard lib needs to consider them.
yeah, I didn't exactly want the PEP to be the pydoc of ipaddr, but I did want to explain the features and show how I thought they were important to whatever might be accepted by python. I can certainly go into much more detail in the PEP if that's deemed important. Cheers, /peter
-- Andrew McNamara, Senior Developer, Object Craft http://www.object-craft.com.au/
Andrew McNamara <andrewm <at> object-craft.com.au> writes:
>>> ipaddr.IPv4Network('192.168.1.1/16').network IPv4Address('192.168.0.0')
Er, does this mean that taking the `network` attribute from a network object actually gives an address object (not a network)? It looks horribly misleading to me.
On Tue, 15 Sep 2009 at 14:28, Antoine Pitrou wrote:
Andrew McNamara <andrewm <at> object-craft.com.au> writes:
ipaddr.IPv4Network('192.168.1.1/16').network IPv4Address('192.168.0.0')
Er, does this mean that taking the `network` attribute from a network object actually gives an address object (not a network)? It looks horribly misleading to me.
That was my opinion, too. I've always called that number the 'zero' of the network, but other people said that it is usually called the 'network'. I also find it odd to see a 'network' with an IP address of 192.168.1.1. That looks like a host-address-plus-netmask to me, not a network address. --David
R. David Murray wrote:
On Tue, 15 Sep 2009 at 14:28, Antoine Pitrou wrote:
Andrew McNamara <andrewm <at> object-craft.com.au> writes:
ipaddr.IPv4Network('192.168.1.1/16').network IPv4Address('192.168.0.0')
Er, does this mean that taking the `network` attribute from a network object actually gives an address object (not a network)? It looks horribly misleading to me.
That was my opinion, too. I've always called that number the 'zero' of the network, but other people said that it is usually called the 'network'.
I also find it odd to see a 'network' with an IP address of 192.168.1.1. That looks like a host-address-plus-netmask to me, not a network address.
It just happened that I needed a tool today to calculate the gateway IP for an interface, and I took it as an opportunity to try out this ipaddr module. I'll attempt to relate my experience below... I have to concur with the opinions above. I was very confused by the following error:
addr = ipaddr.IPAddress("10.1.2.3/255.255.240.0") ... ipaddr.IPAddressIPValidationError: '98.223.189.24/255.255.240.0' is not a valid address (hint, it's probably a network)
Because, it *is* a address of a host on a network. I gave in and said:
net = ipaddr.IPNetwork("10.1.2.3/255.255.240.0")
But then, I was dumbfounded as to how I could get the gateway IP from this IPNetwork object. It took me a while to figure out that you can iterate over IPNetwork instances:
gateway = net[1]
I was then confused, because:
print(type(gateway)) <class 'ipaddr.IPv4Address'>
Which sorta blew my mind.. I fully expected to receive an IPNetwork back from that operation. It is unclear to me why the network information gets chucked by that operation. I foresee having to work around that in real applications by doing something obnoxious like:
actual_gateway = ipaddr.IPNetwork("%s/%s" % (gateway, addr.netmask))
But since I only actually needed the IP address for the gateway, it fulfilled my needs. In the end, I found the names IPNetwork/IPAddress and their instantiations confusing. ISTM that IPNetwork is overloaded and plays two roles of being an IPNetwork and being an IPAddressWithNetwork. And finally, it's unclear to me why iterating over a IPNetwork would not produce a sequence of IPNetwork(/IPAddressWithNetwork) objects. ISTM that if I started with an IPNetwork object, the API should always return IPNetwork objects. If I want just an IPAddress object, then I can always fetch the "ip" attribute to get that. Perhaps there is some compelling conceptual argument as to why this is not correct, but it seems like the API destroys information needlessly. Just my opinion.. -- Scott Dial scott@scottdial.com scodial@cs.indiana.edu
On Tue, Sep 15, 2009 at 10:16 AM, Scott Dial <scott+python-dev@scottdial.com> wrote:
R. David Murray wrote:
On Tue, 15 Sep 2009 at 14:28, Antoine Pitrou wrote:
Andrew McNamara <andrewm <at> object-craft.com.au> writes:
>>> ipaddr.IPv4Network('192.168.1.1/16').network IPv4Address('192.168.0.0')
Er, does this mean that taking the `network` attribute from a network object actually gives an address object (not a network)? It looks horribly misleading to me.
That was my opinion, too. I've always called that number the 'zero' of the network, but other people said that it is usually called the 'network'.
I also find it odd to see a 'network' with an IP address of 192.168.1.1. That looks like a host-address-plus-netmask to me, not a network address.
It just happened that I needed a tool today to calculate the gateway IP for an interface, and I took it as an opportunity to try out this ipaddr module. I'll attempt to relate my experience below...
I have to concur with the opinions above. I was very confused by the following error:
addr = ipaddr.IPAddress("10.1.2.3/255.255.240.0") ... ipaddr.IPAddressIPValidationError: '98.223.189.24/255.255.240.0' is not a valid address (hint, it's probably a network)
are you actually getting '98.223.189.24/255.255.240.0' back? that doesn't look right.
Because, it *is* a address of a host on a network. I gave in and said:
net = ipaddr.IPNetwork("10.1.2.3/255.255.240.0")
But then, I was dumbfounded as to how I could get the gateway IP from this IPNetwork object. It took me a while to figure out that you can iterate over IPNetwork instances:
gateway = net[1]
I was then confused, because:
print(type(gateway)) <class 'ipaddr.IPv4Address'>
Which sorta blew my mind.. I fully expected to receive an IPNetwork back from that operation. It is unclear to me why the network information gets chucked by that operation. I foresee having to work around that in real applications by doing something obnoxious like:
actual_gateway = ipaddr.IPNetwork("%s/%s" % (gateway, addr.netmask))
But since I only actually needed the IP address for the gateway, it fulfilled my needs.
In the end, I found the names IPNetwork/IPAddress and their instantiations confusing. ISTM that IPNetwork is overloaded and plays two roles of being an IPNetwork and being an IPAddressWithNetwork. And finally, it's unclear to me why iterating over a IPNetwork would not produce a sequence of IPNetwork(/IPAddressWithNetwork) objects.
What you're describing, at least for the networks, is basically what ipaddr was. It seemed, after much heated discussion, that the community felt that ipaddr.IPv4Network('1.1.1.0/24')[0] was actually an individual address. ie, each of the addresses in 1.1.1.0/24 are individual addresses, rather than networks with /32 prefix lengths. having said that, I understand your confusion; I spent a year+ treating addresses exactly as you've mentioned. It didn't seem as though the majority of the community felt the same, though, so ipaddr evolved. Cheers, /peter
ISTM that if I started with an IPNetwork object, the API should always return IPNetwork objects. If I want just an IPAddress object, then I can always fetch the "ip" attribute to get that. Perhaps there is some compelling conceptual argument as to why this is not correct, but it seems like the API destroys information needlessly.
Just my opinion..
-- Scott Dial scott@scottdial.com scodial@cs.indiana.edu _______________________________________________ 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 Tue, Sep 15, 2009 at 10:16 AM, Scott Dial <scott+python-dev@scottdial.com> wrote:
In the end, I found the names IPNetwork/IPAddress and their instantiations confusing. ISTM that IPNetwork is overloaded and plays two roles of being an IPNetwork and being an IPAddressWithNetwork. And finally, it's unclear to me why iterating over a IPNetwork would not produce a sequence of IPNetwork(/IPAddressWithNetwork) objects.
What you're describing, at least for the networks, is basically what ipaddr was. It seemed, after much heated discussion, that the community felt that
ipaddr.IPv4Network('1.1.1.0/24')[0]
was actually an individual address. ie, each of the addresses in 1.1.1.0/24 are individual addresses, rather than networks with /32 prefix lengths.
For clarity, I am going to call the current design "A": ipaddr.IPv4Network('1.1.1.0/24')[0] == ipaddr.IPv4Address('1.1.1.0') And what itt sounds like what you are describing as the old behavior is this (design "B"): ipaddr.IPv4Network('1.1.1.0/24')[0] == ipaddr.IPv4Network('1.1.1.0/32') Which is different than what I was trying to describe. I expected (design "C"): ipaddr.IPv4Network('1.1.1.0/24')[0] == ipaddr.IPv4Network('1.1.1.0/24') My summarization of these designs would be that "B" is wrong. And that "A" is better than "B", certainly. At least "A" is not saying something untrue. However, "C" would be truthful and retains a superset of information that "A" provides (the "ip" attribute of IPNetwork). In other words, I don't see why obtaining a host address would *not* retain the hostmask from the network it was obtained from. I am not disagreeing with it being an individual address. I am disagreeing that IPNetwork itself already does represent individual addresses (hence my aliasing it with IPAddressWithNetwork). And wrt, the logical return would be another IPAddressWithNetwork retaining the same mask. -- Scott Dial scott@scottdial.com scodial@cs.indiana.edu
On Tue, 15 Sep 2009 at 14:16, Scott Dial wrote:
In other words, I don't see why obtaining a host address would *not* retain the hostmask from the network it was obtained from. I am not disagreeing with it being an individual address. I am disagreeing that IPNetwork itself already does represent individual addresses (hence my aliasing it with IPAddressWithNetwork). And wrt, the logical return would be another IPAddressWithNetwork retaining the same mask.
In other other words, maybe we have three data types: IPv4Address IPv4AddressWithMask IPv4Network Where myAddressWithMask.network would return an IPv4Network object, and an IPv4Network object would always have the zero of the network as its representation: x = IPv4AddressWithMask('192.168.1.1/24') x.network == IPv4Network('192.168.1.0/24') x.network[1] == x In this scheme, IPv4Network('192.168.1.1/24') would raise a ValueError. Although you could probably have what I called IPv4AddressWithMask be called IPv4Address, and have what is now IPv4Address just have netmask and network attributes of None. If this were done, I would expect IPv4Network.network to be either an attribute error or return self. --David
R. David Murray <rdmurray <at> bitdance.com> writes:
x = IPv4AddressWithMask('192.168.1.1/24') x.network == IPv4Network('192.168.1.0/24') x.network[1] == x
I don't think we need an IPAddressWithMask which would just complicate the API without any obvious benefit. We just need a factory function which returns a tuple after parsing: >>> addr, net = parse_address_with_mask('192.168.1.1/24') >>> addr == IPv4Address('192.168.1.1') True >>> net == IPv4Network('192.168.1.0/24') True Regards Antoine.
On Tue, 15 Sep 2009 at 18:43, Antoine Pitrou wrote:
R. David Murray <rdmurray <at> bitdance.com> writes:
x = IPv4AddressWithMask('192.168.1.1/24') x.network == IPv4Network('192.168.1.0/24') x.network[1] == x
I don't think we need an IPAddressWithMask which would just complicate the API without any obvious benefit. We just need a factory function which returns a tuple after parsing:
addr, net = parse_address_with_mask('192.168.1.1/24') addr == IPv4Address('192.168.1.1') True net == IPv4Network('192.168.1.0/24') True
I would find that acceptable but sub-optimal. Most of my use cases (which involve manipulating router and firewall configuration files) would then start by making a little class named AddressWithNetwork to hold the tuple returned by your parse function, with attributes 'ip' and 'network' and a representation that included the netmask. Other people's use cases would look like addr, _ = parse_address... An IPv4Address with 'network' and 'mask' attributes that could be None would also not complicate the API, IMO, and would handle both of these use cases. --David
R. David Murray <rdmurray <at> bitdance.com> writes:
I would find that acceptable but sub-optimal. Most of my use cases (which involve manipulating router and firewall configuration files) would then start by making a little class named AddressWithNetwork to hold the tuple returned by your parse function, with attributes 'ip' and 'network' and a representation that included the netmask.
If the AddressWithNetwork class has useful functionality of its own, then why not (although I think that conceptually, this functionality should belong to the Network class instead). If, however, the AddressWithNetwork class is only a recipient for a tuple, then it sounds useless. It's like having an AddressWithPort to hold things like "127.0.0.1:8080". Building little featureless recipients like that isn't really idiomatic Python, IMO.
An IPv4Address with 'network' and 'mask' attributes that could be None would also not complicate the API, IMO, and would handle both of these use cases.
But it would be confusing and conceptually bizarre, because an address (in usually accepted terminology) doesn't have a network and a mask. I think we should keep the API clean and reasonably logical, rather than try to cover all use cases at the expense of weird shortcuts. Regards Antoine.
On Tue, 15 Sep 2009 at 19:20, Antoine Pitrou wrote:
R. David Murray <rdmurray <at> bitdance.com> writes:
I would find that acceptable but sub-optimal. Most of my use cases (which involve manipulating router and firewall configuration files) would then start by making a little class named AddressWithNetwork to hold the tuple returned by your parse function, with attributes 'ip' and 'network' and a representation that included the netmask.
If the AddressWithNetwork class has useful functionality of its own, then why not (although I think that conceptually, this functionality should belong to the Network class instead).
But it's not a network. It's an address that is explicitly associated with a network. It's useful functionality is parsing/validating an address+mask, rendering as address+mask, and being able to get the associated IP and network objects from it. It's a small class, but useful, IMO.
If, however, the AddressWithNetwork class is only a recipient for a tuple, then it sounds useless. It's like having an AddressWithPort to hold things like "127.0.0.1:8080". Building little featureless recipients like that isn't really idiomatic Python, IMO.
I could see myself doing that, too, though I haven't had a reason to yet :) Although I'd probably call it 'IPv4EndPoint' or some such, since it would be representing one endpoint of a traffic flow...
An IPv4Address with 'network' and 'mask' attributes that could be None would also not complicate the API, IMO, and would handle both of these use cases.
But it would be confusing and conceptually bizarre, because an address (in usually accepted terminology) doesn't have a network and a mask. I think we should keep the API clean and reasonably logical, rather than try to cover all use cases at the expense of weird shortcuts.
OK. I'll withdrawal that suggestion. If AddressWithMask doesn't get added I won't be heartbroken; it is easy enough to write in the programs where I need it (at least it would be if the parsing/validation is in the library). However, I do not think that the proposed API should accept, eg, IPv4Network('192.168.1.1/24') as valid. That's just too confusing and error prone. Oh, and if people don't like 'zero' as the name for the IPv4Address at the beginning of the network IP range, how about 'network_ip' or 'network_address' instead of just network, to make it clearer that it is an address? --David
Le mardi 15 septembre 2009 à 15:48 -0400, R. David Murray a écrit :
It's useful functionality is parsing/validating an address+mask, rendering as address+mask, and being able to get the associated IP and network objects from it. It's a small class, but useful, IMO.
If it's only about parsing and validating, then a tuple works just fine. Getting the associated IP objects is obtained from iterating over the network. Getting the associated network objects I don't understand. There is a single network, not a bunch of them.
However, I do not think that the proposed API should accept, eg, IPv4Network('192.168.1.1/24') as valid. That's just too confusing and error prone.
Indeed, it should throw some kind of ValueError instead.
Oh, and if people don't like 'zero' as the name for the IPv4Address at the beginning of the network IP range, how about 'network_ip' or 'network_address' instead of just network, to make it clearer that it is an address?
How about something more explicit about how it's obtained, like 'lower_bound'?
On Tue, 15 Sep 2009 at 21:58, Antoine Pitrou wrote:
Le mardi 15 septembre 2009 à 15:48 -0400, R. David Murray a écrit :
It's useful functionality is parsing/validating an address+mask, rendering as address+mask, and being able to get the associated IP and network objects from it. It's a small class, but useful, IMO.
If it's only about parsing and validating, then a tuple works just fine. Getting the associated IP objects is obtained from iterating over the network. Getting the associated network objects I don't understand. There is a single network, not a bunch of them.
The plural was for the two attributes. I guess I just like accessing things by name better than accessing them by indexes. I suppose a NamedTuple would work. Anyway, like I said I'm not attached to that class.
However, I do not think that the proposed API should accept, eg, IPv4Network('192.168.1.1/24') as valid. That's just too confusing and error prone.
Indeed, it should throw some kind of ValueError instead.
Peter, what do you think?
Oh, and if people don't like 'zero' as the name for the IPv4Address at the beginning of the network IP range, how about 'network_ip' or 'network_address' instead of just network, to make it clearer that it is an address?
How about something more explicit about how it's obtained, like 'lower_bound'?
Well, when this came up earlier 'first' and 'last' were suggested to replace 'network' and 'broadcast', but that proposal didn't get much traction, the argument being that in normal technical parlance the first IP in the netblock is (apparently, this isn't my personal experience(*)) called the network, and the broadcast is almost invariably the last IP in the netblock (and that does agree with my experience). --David (*) in my experience it is called the "network number", which I gather derives from the pre-CIDR days. "network identifier" also appears to be used. In my experience "network" refers to something that has a netmask, although the netmask may be implicit in its class in the classful routing sense, or through other context. Consider this article, for example: http://compnetworking.about.com/od/workingwithipaddresses/l/aa042900a.htm
R. David Murray wrote:
On Tue, 15 Sep 2009 at 21:58, Antoine Pitrou wrote:
Le mardi 15 septembre 2009 à 15:48 -0400, R. David Murray a écrit :
However, I do not think that the proposed API should accept, eg, IPv4Network('192.168.1.1/24') as valid. That's just too confusing and error prone.
Indeed, it should throw some kind of ValueError instead.
Peter, what do you think?
This change would have to be dependent on Antoine's suggestion of: >>> addr, net = parse_address_with_mask('192.168.1.1/24') >>> addr == IPv4Address('192.168.1.1') True >>> net == IPv4Network('192.168.1.0/24') True Otherwise, I am ok with this change too. It resloves the weird duality of IPv4Network. And as RDM says, anyone who wants the IPv4AddressWithNetwork functionality can just role it themselves. At the moment of iteration, you have access to what network it is and can build your own IPv4AddressWithNetwork objects. net = IPv4Network('10.0.0.0/24') netaddrs = [] for addr in net: netaddrs.append(IPv4AddressWithNetwork(addr, net)) I guess I am ok with this. It seems sub-optimal (why not just return a IPv4AddressWithNetwork to begin with?) but I suppose it is no less efficient since the same objects would be constructed. -- Scott Dial scott@scottdial.com scodial@cs.indiana.edu
On Tue, Sep 15, 2009 at 4:34 PM, Scott Dial <scott+python-dev@scottdial.com> wrote:
R. David Murray wrote:
On Tue, 15 Sep 2009 at 21:58, Antoine Pitrou wrote:
Le mardi 15 septembre 2009 à 15:48 -0400, R. David Murray a écrit :
However, I do not think that the proposed API should accept, eg, IPv4Network('192.168.1.1/24') as valid. That's just too confusing and error prone.
Indeed, it should throw some kind of ValueError instead.
Peter, what do you think?
I disagree. It seems overly pedantic to throw a valueerror on this. IPy does (used to do?) this and it's one of the primary reasons I wrote ipaddr.
This change would have to be dependent on Antoine's suggestion of:
>>> addr, net = parse_address_with_mask('192.168.1.1/24') >>> addr == IPv4Address('192.168.1.1') True >>> net == IPv4Network('192.168.1.0/24') True
Otherwise, I am ok with this change too. It resloves the weird duality of IPv4Network. And as RDM says, anyone who wants the IPv4AddressWithNetwork functionality can just role it themselves. At the moment of iteration, you have access to what network it is and can build your own IPv4AddressWithNetwork objects.
now, I understand that as the author, I have certain biases, but I'm not having the same difficulty with this duality as others. I really don't even see it as a duality. It seems as though your issue could more easily be solved by having an iterator in BaseNet which returns a new network object with the original prefix length. eg: for addr in ipaddr.IPv4Network('1.1.1.0/24').iterwithnetmask(): # 1.1.1.0/24, 1.1.1.1/24, 1.1.1.2/24... (or better yet, .iterwithprefix) this can be done much more cleanly/easily than adding two new (redundant in my eyes) classes and much less pedantically than raising exceptions w/ IPv?Network() constructor received something other than base network address. Is this sufficient? If not, perhaps someone could help me better understand the confusion over IPv?Network objects. Cheers, /peter
net = IPv4Network('10.0.0.0/24') netaddrs = [] for addr in net: netaddrs.append(IPv4AddressWithNetwork(addr, net))
I guess I am ok with this. It seems sub-optimal (why not just return a IPv4AddressWithNetwork to begin with?) but I suppose it is no less efficient since the same objects would be constructed.
-- Scott Dial scott@scottdial.com scodial@cs.indiana.edu _______________________________________________ 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 <peter <at> hda3.com> writes:
However, I do not think that the proposed API should accept, eg, IPv4Network('192.168.1.1/24') as valid. That's just too confusing and error prone.
Indeed, it should throw some kind of ValueError instead.
Peter, what do you think?
I disagree. It seems overly pedantic to throw a valueerror on this. IPy does (used to do?) this and it's one of the primary reasons I wrote ipaddr.
Python is not PHP and does not try to be overly "smart" or tolerant when faced with bizarrely-formatted input. I don't see any valid reason for entering a network as "192.168.1.1/24" rather than the canonical "192.168.1.0/24". The former might indicate a typing error or a mental slip, so let's be helpful and signal it to the user.
for addr in ipaddr.IPv4Network('1.1.1.0/24').iterwithnetmask(): # 1.1.1.0/24, 1.1.1.1/24, 1.1.1.2/24...
I don't have any strong feelings about it, although I don't really think it is needed, and a plethoric API is not a good thing (neither clarity-wise nor maintenance-wise).
this can be done much more cleanly/easily than adding two new (redundant in my eyes) classes and much less pedantically than raising exceptions w/ IPv?Network() constructor received something other than base network address.
I don't think anybody suggested adding two classes. As for the "pedantry" of thoroughly validating inputs, see above. Regards Antoine.
Antoine Pitrou <solipsis <at> pitrou.net> writes:
I don't see any valid reason for entering a network as "192.168.1.1/24" rather than the canonical "192.168.1.0/24". The former might indicate a typing error or a mental slip, so let's be helpful and signal it to the user.
Or perhaps there can be an optional "strict=True" (or "strict=False") argument to the constructor / parsing function. Regards Antoine.
Antoine Pitrou wrote:
Antoine Pitrou <solipsis <at> pitrou.net> writes:
I don't see any valid reason for entering a network as "192.168.1.1/24" rather than the canonical "192.168.1.0/24". The former might indicate a typing error or a mental slip, so let's be helpful and signal it to the user.
Or perhaps there can be an optional "strict=True" (or "strict=False") argument to the constructor / parsing function.
If so, I hope that we'd default to strict=True.
I don't see any valid reason for entering a network as "192.168.1.1/24" rather than the canonical "192.168.1.0/24". The former might indicate a typing error or a mental slip, so let's be helpful and signal it to the user.
Or perhaps there can be an optional "strict=True" (or "strict=False") argument to the constructor / parsing function.
If so, I hope that we'd default to strict=True.
I don't see the point of enforcing strictness here. There are good use cases: if you know your address is 82.94.164.162, how do you compute what you should spell for 82.94.164.162/27? It's very easy to make a mistake here, and doing the computation in your head is really not something that should be necessary, given that a computer can get it correct easily. Regards, Martin
On Tue, Sep 15, 2009 at 5:33 PM, Antoine Pitrou <solipsis@pitrou.net> wrote:
Antoine Pitrou <solipsis <at> pitrou.net> writes:
I don't see any valid reason for entering a network as "192.168.1.1/24" rather than the canonical "192.168.1.0/24". The former might indicate a typing error or a mental slip, so let's be helpful and signal it to the user.
Or perhaps there can be an optional "strict=True" (or "strict=False") argument to the constructor / parsing function.
I can live w/ a default of strict=False. there are plenty of cases where it's not an error and easy enough ways to check, if the developer is concerned, with or without an option. eg if addr.ip != addr.network: Cheers, /peter
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/python-dev%40hda3.com
I don't see any valid reason for entering a network as "192.168.1.1/24" rather than the canonical "192.168.1.0/24". The former might indicate a typing error or a mental slip, so let's be helpful and signal it to the user.
Or perhaps there can be an optional "strict=True" (or "strict=False") argument to the constructor / parsing function.
I can live w/ a default of strict=False. there are plenty of cases where it's not an error and easy enough ways to check, if the developer is concerned, with or without an option. eg if addr.ip != addr.network:
I agree - there are definitely times when it is not an error, but I don't like the idea of a "strict" flag. I've done a bit of everything - router configs with a national ISP, scripts to manage host configuration, user interfaces, you name it. The way I see it, we need: * Two address classes that describe a single IP end-point - "Address" with no mask and "AddressWithMask" (the later being the current Network class, minus the container-like behaviour). * A "Network" container-like class. Same as the current Network class, but addresses with masked bits would be considered an error. This is along the lines that RDM was suggesting, except that we remove the container behaviour from AddressWithMask. Additionally: * The .network attribute on an AddressWithMask would return a Network instance. * An Address class would not have a .network attribute * Network.__contains__() would accept Network, Address and AddressWithMask. Only Network implements __contains__ - an AddressWithMask can't contain another address, although it's .network can. * Maybe an Address should compare equal with an AddressWithMask if the address is identical and the mask is equivalent to /32? Personally, I don't see a strong use-case for the list-like indexing and iteration behaviour - I think it's enough to implement some basic container behaviour, but I won't object to the iterator and indexing, provided they don't distort the rest of the design (which I fear they are doing now). Iterating or indexing a network should return Address or AddressWithMask instances - if the later, the mask should match the parent network's mask. I'm not particularly wedded to the name "AddressWithMask" - maybe it could be NetworkAddress or MaskedAddress or ? -- Andrew McNamara, Senior Developer, Object Craft http://www.object-craft.com.au/
I'd like to see more clear direction for this. Is it a string manipulation library, or an IP address library? There are ONLY TWO types of IP representations: 1. Network = 32 bit number AND 32 bit mask. That is the binary AND. The mask needs to be preserved, but not the network portion. Any library should return the ANDed result. Whether the number is 192.186.1.1/24 or 192.168.1.0/24, the result after 'and' is the same. Add a strict=false in case people need it for validation, better yet, add a validation helper function, but always return the proper form. 2. A host address is an IP address with no network info. No mask information, ever. What about Broadcast / Network IDs? The "Network-ID or Network Number" and "Broadcast" are meaningless without context. 1. A network number by itself it's just another address. Its use depends on context. When routing, it needs a mask.
route 10.0.0.0 255.0.0.0 192.168.1.1
When writing firewall ACLs, it is a host.
access-list aclname permit ip any 192.168.1.2 255.255.255.254
Since both are valid, preference shouldn't be given. Instead add a helper for firstip. 2. Same story with broadcast. Use depends on context. Add the lastip helper. What does iterating over a network mean? Iterating over the set of addresses in a network must return host addresses. If it returns a network, then the address should be ANDed, but that would return the same number for every iteration. Only returning hosts makes sense. We need to set a solid line between IP String manipulation and IP manipulation. If you want an IP with a mask that isn't a network, then you're not doing IP address manipulation, you're doing string manipulation. There are many use cases for it, but it's a separate consideration to pure IP manipulation. If string manipulation is desirable, then add another standard library called ipstring (or a separate class if you want it all jumbled in the same import). This way real network computing can be done without weird quirks of representation. R.
Antoine Pitrou wrote:
Peter Moody <peter <at> hda3.com> writes:
However, I do not think that the proposed API should accept, eg, IPv4Network('192.168.1.1/24') as valid. That's just too confusing and error prone. Indeed, it should throw some kind of ValueError instead. Peter, what do you think? I disagree. It seems overly pedantic to throw a valueerror on this. IPy does (used to do?) this and it's one of the primary reasons I wrote ipaddr.
Python is not PHP and does not try to be overly "smart" or tolerant when faced with bizarrely-formatted input.
I don't see any valid reason for entering a network as "192.168.1.1/24" rather than the canonical "192.168.1.0/24". The former might indicate a typing error or a mental slip, so let's be helpful and signal it to the user.
I completely agree. I don't know of any situation where I'd want a network of "192.168.1.1/24" to be anything other than an error. Eric.
On Tue, Sep 15, 2009 at 6:02 PM, Eric Smith <eric@trueblade.com> wrote:
Antoine Pitrou wrote:
Peter Moody <peter <at> hda3.com> writes:
> > However, I do not think > that the proposed API should accept, eg, > IPv4Network('192.168.1.1/24') > as valid. That's just too confusing and error prone.
Indeed, it should throw some kind of ValueError instead.
Peter, what do you think?
I disagree. It seems overly pedantic to throw a valueerror on this. IPy does (used to do?) this and it's one of the primary reasons I wrote ipaddr.
Python is not PHP and does not try to be overly "smart" or tolerant when faced with bizarrely-formatted input.
I don't see any valid reason for entering a network as "192.168.1.1/24" rather than the canonical "192.168.1.0/24". The former might indicate a typing error or a mental slip, so let's be helpful and signal it to the user.
I completely agree. I don't know of any situation where I'd want a network of "192.168.1.1/24" to be anything other than an error.
when you're entering the address of your nic.
Eric. _______________________________________________ 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
I've been skimming emails in this thread, since most of them go over my head and I have no current need for an ipaddress module. But one thing I noticed stands out and needs commenting on: On Wed, 16 Sep 2009 11:05:26 am Peter Moody wrote:
On Tue, Sep 15, 2009 at 6:02 PM, Eric Smith <eric@trueblade.com> wrote:
I completely agree. I don't know of any situation where I'd want a network of "192.168.1.1/24" to be anything other than an error.
when you're entering the address of your nic.
Eric is talking about a network. Peter replies by talking about an address. Perhaps I'm naive, but surely addresses aren't networks? If Peter's use-case is to treat addresses and networks interchangeably, I can't imagine that could be a good thing. Is it? What do the relevant RFCs say? As an outsider to this argument, and judging from the lack of agreement here, it seems to me that some (many? most?) developers who have need of ipaddress functions are a little unclear about the difference, or lack thereof, between addresses and networks. Is it our aim to pander to such confusion, and have a module which will Just Work for such users, even at the risk of sometimes accepting invalid input. Or is it to have a module which is strict and forces the user to Do The Right Thing, even at the cost of being less easy to use? For what it's worth, it seems to me that it would be better to have a strict module in the standard lib, and leave the DWIM code to third parties. -- Steven D'Aprano
2009/9/16 Steven D'Aprano <steve@pearwood.info>:
I've been skimming emails in this thread, since most of them go over my head and I have no current need for an ipaddress module.
Same here.
As an outsider to this argument, and judging from the lack of agreement here, it seems to me that some (many? most?) developers who have need of ipaddress functions are a little unclear about the difference, or lack thereof, between addresses and networks. Is it our aim to pander to such confusion, and have a module which will Just Work for such users, even at the risk of sometimes accepting invalid input. Or is it to have a module which is strict and forces the user to Do The Right Thing, even at the cost of being less easy to use?
For what it's worth, it seems to me that it would be better to have a strict module in the standard lib, and leave the DWIM code to third parties.
As a non-expert, I find the confusion between network, address, address with mask, etc to be extremely unhelpful. I haven't looked to confirm if it's a confusion that only exists in the discussion, or if it's in the code as well. However, from my POV, I'd rather have a module that made the concepts clear and unambiguous, effectively educating me in the details of correct usage while I used it, rather than one that catered to my muddled thinking and allowed me to remain confused. Of course, the discussion seems to imply that even the experts have a confused view, so maybe I'm being too ambitious here :-) Paul.
On Wed, 16 Sep 2009 at 12:04, Paul Moore wrote:
Of course, the discussion seems to imply that even the experts have a confused view, so maybe I'm being too ambitious here :-)
Part of the problem, as we discovered in the last go-round on ipaddr, is that there are two types of experts: those who primarily deal with networks and for whom host addresses are just a special case, and those who primarily deal with host addresses, for whom networks are relevant only in certain contexts. I hope we are converging on something that works for both. That should certainly be a goal, since the fact that it didn't was what scuttled inclusion last time. --David
Steven D'Aprano wrote:
I've been skimming emails in this thread, since most of them go over my head and I have no current need for an ipaddress module. But one thing I noticed stands out and needs commenting on:
On Wed, 16 Sep 2009 11:05:26 am Peter Moody wrote:
On Tue, Sep 15, 2009 at 6:02 PM, Eric Smith <eric@trueblade.com> wrote:
I completely agree. I don't know of any situation where I'd want a network of "192.168.1.1/24" to be anything other than an error. when you're entering the address of your nic.
Eric is talking about a network. Peter replies by talking about an address.
Martin explained it better in another part of the thread:
if you know your address is 82.94.164.162, how do you compute what you should spell for 82.94.164.162/27?
Or, to put it another way, given an arbitrary host in a network (e.g. your own machine or the default gateway) and the netmask for that network, calculate the network address. With a "lax" parser on IPNetwork this is a trivial task - just create the network object and then retrieve the network address from it. If, on the other hand, IPNetwork demands that you already know the network address before allowing you to create an IPNetwork object, then you're pretty much out of luck - if all you have to work with are the IP strings then this is actually a tricky calculation. If the default IPNetwork constructor was made more strict, then this functionality would have to be made available another way (probably as an alternate constructor like IPNetwork.from_host_address rather than as a boolean 'strict' option) Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia ---------------------------------------------------------------
On 11:10 am, ncoghlan@gmail.com wrote:
Steven D'Aprano wrote:
I've been skimming emails in this thread, since most of them go over my head and I have no current need for an ipaddress module. But one thing I noticed stands out and needs commenting on:
On Wed, 16 Sep 2009 11:05:26 am Peter Moody wrote:
On Tue, Sep 15, 2009 at 6:02 PM, Eric Smith <eric@trueblade.com> wrote:
I completely agree. I don't know of any situation where I'd want a network of "192.168.1.1/24" to be anything other than an error. when you're entering the address of your nic.
Eric is talking about a network. Peter replies by talking about an address.
Martin explained it better in another part of the thread:
if you know your address is 82.94.164.162, how do you compute what you should spell for 82.94.164.162/27?
Or, to put it another way, given an arbitrary host in a network (e.g. your own machine or the default gateway) and the netmask for that network, calculate the network address.
With a "lax" parser on IPNetwork this is a trivial task - just create the network object and then retrieve the network address from it.
If, on the other hand, IPNetwork demands that you already know the network address before allowing you to create an IPNetwork object, then you're pretty much out of luck - if all you have to work with are the IP strings then this is actually a tricky calculation.
If the default IPNetwork constructor was made more strict, then this functionality would have to be made available another way (probably as an alternate constructor like IPNetwork.from_host_address rather than as a boolean 'strict' option)
This seems to be the right solution to me, particularly the use of an alternate constructor rather than an ambiguously named flag. Jean-Paul
exarkun@twistedmatrix.com wrote:
On 11:10 am, ncoghlan@gmail.com wrote:
If the default IPNetwork constructor was made more strict, then this functionality would have to be made available another way (probably as an alternate constructor like IPNetwork.from_host_address rather than as a boolean 'strict' option)
This seems to be the right solution to me, particularly the use of an alternate constructor rather than an ambiguously named flag.
Particular since someone pointed out that the "Network" object was remembering which IP address happened to be passed to the constructor (which is "Address with Mask" behaviour, as has been mentioned). That said, I've been trying to refrain from commenting on specifics of the API, as I haven't tried to use it for anything. Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia ---------------------------------------------------------------
On Wed, 16 Sep 2009 at 12:50, exarkun@twistedmatrix.com wrote:
On 11:10 am, ncoghlan@gmail.com wrote:
Or, to put it another way, given an arbitrary host in a network (e.g. your own machine or the default gateway) and the netmask for that network, calculate the network address.
With a "lax" parser on IPNetwork this is a trivial task - just create the network object and then retrieve the network address from it.
If, on the other hand, IPNetwork demands that you already know the network address before allowing you to create an IPNetwork object, then you're pretty much out of luck - if all you have to work with are the IP strings then this is actually a tricky calculation.
If the default IPNetwork constructor was made more strict, then this functionality would have to be made available another way (probably as an alternate constructor like IPNetwork.from_host_address rather than as a boolean 'strict' option)
This seems to be the right solution to me, particularly the use of an alternate constructor rather than an ambiguously named flag.
+1 --David
Nick Coghlan wrote:
Or, to put it another way, given an arbitrary host in a network (e.g. your own machine or the default gateway) and the netmask for that network, calculate the network address.
Some people have claimed that the gateway address of a network isn't necessarily the zero address in that network. If that's true, then you *can't* calculate the network address from a host address and a netmask -- there isn't enough information. Furthermore, an IPNetwork object needs to be able to represent a network address whose address part contains bits that aren't in the mask. -- Greg
On Thu, 17 Sep 2009 at 09:59, Greg Ewing wrote:
Nick Coghlan wrote:
Or, to put it another way, given an arbitrary host in a network (e.g. your own machine or the default gateway) and the netmask for that network, calculate the network address.
Some people have claimed that the gateway address of a network isn't necessarily the zero address in that network. If that's true, then you *can't* calculate the network address from a host address and a netmask -- there isn't enough information. Furthermore, an IPNetwork object needs to be able to represent a network address whose address part contains bits that aren't in the mask.
A 'gateway' is an IP (ie: host) in a network to which you route packets for delivery elsewhere. That's a very different thing from the 'network number' (or 'network address' or 'network zero' or 'network identifier' or whatever you want to call it). Any IP in a network can be a gateway IP, and in many networks there is more than one gateway (and thus the need for routing tables...) A network is conventionally represented by an IP address in which the bits corresponding to the one bits in the netmask are set to zero, plus the netmask. That IP with the bits set to zero is the 'network number' or zero for the network, and it is almost never used as the address for a host in the network. Thus it would be very surprising to find it being used as a gateway address. There is no reason why an IPNetwork object should record any bits from the portion of the IP address that are covered by the mask bits. To do otherwise is to conflate Networks with individual IPs, which is what got IPAddr rejected the first time around. (And for those of you who don't know/remember, I was initially an IPAddr booster in its original incarnation, because I come from a network engineering background.) This existence of this kind of confusion is why I voted +1 for the IPNetwork constructor rejecting input with non-zero bits covered by the mask, and a separate constructor method to return the network object representing the network that a given IP address is in when a given mask is applied to it. (Which is easily computed by applying the mask to the IP.) --David
R. David Murray wrote:
A network is conventionally represented by an IP address in which the bits corresponding to the one bits in the netmask are set to zero, plus the netmask.
Okay, that's clarified things for me, thanks. In that case, we shouldn't be talking about a "network address" at all, but just a "network", and it makes sense to have 1) A class called IPNetwork that contains an IP number and a mask, with the IP number constrained not to have any ones where the mask has zeroes, and 2) A class called IPAddress which only contains an IP number. It seems that some people would also like to have 3) A class called IPAddressWithMask that contains an IP number and a mask, with no constraints, but I'm not enough of an expert to know whether such a thing would be used often enough to be worth having a special type for it, as opposed to using an (IPNetwork, IPAddress) pair, or attaching a 'network' attribute to an IPAddress, or some other solution when the need arises. -- Greg
R. David Murray wrote:
A network is conventionally represented by an IP address in which the bits corresponding to the one bits in the netmask are set to zero, plus the netmask.
Okay, that's clarified things for me, thanks.
Put another way, an "Address" describes a single end-point and a "Network" describes a set of (contiguous) Addresses. Where things have become confused is that, for practical reasons, it is convenient to have a representation for an Address and it's containing Network (the later can be derived from the Address and a mask). We tried to make the current Network entity do double-duty, but it is just leading to confusion. This is why I proprose there be three entities: * an Address entity (same as the current one) * a Network entity (like now, but requires masked bits to be zero) * an AddressWithMask entity (existing Network, but no container behaviour) There is a school of thought that says we only need a single class that behaves like the current Network entity - end-points are simply represented by an all-ones mask. This is, I think, where we started. But this scheme was rejected. -- Andrew McNamara, Senior Developer, Object Craft http://www.object-craft.com.au/
On Wed, Sep 16, 2009 at 5:30 PM, Andrew McNamara <andrewm@object-craft.com.au> wrote:
R. David Murray wrote:
A network is conventionally represented by an IP address in which the bits corresponding to the one bits in the netmask are set to zero, plus the netmask.
Okay, that's clarified things for me, thanks.
Put another way, an "Address" describes a single end-point and a "Network" describes a set of (contiguous) Addresses.
Where things have become confused is that, for practical reasons, it is convenient to have a representation for an Address and it's containing Network (the later can be derived from the Address and a mask). We tried to make the current Network entity do double-duty, but it is just leading to confusion.
This is why I proprose there be three entities:
* an Address entity (same as the current one) * a Network entity (like now, but requires masked bits to be zero) * an AddressWithMask entity (existing Network, but no container behaviour)
This proposal actually leads to 6 entities (3 for IPv4 and 3 for IPv6). It's still unclear to me what is gained by pulling AddressWithMask functionality out of the current network classes. It's easy enough for the concerned developer who to check if the entered network address does actually have all of its host bits set to zero. It is not my experience that this behavior is desired so often that having the network classes behave as they do now leads to a great deal of confusion.
There is a school of thought that says we only need a single class that behaves like the current Network entity - end-points are simply represented by an all-ones mask. This is, I think, where we started. But this scheme was rejected.
I don't think anything has actually been rejected.
-- Andrew McNamara, Senior Developer, Object Craft http://www.object-craft.com.au/ _______________________________________________ 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
This proposal actually leads to 6 entities (3 for IPv4 and 3 for IPv6).
Yes, I know - I was just trying to keep to the point.
It's still unclear to me what is gained by pulling AddressWithMask functionality out of the current network classes. It's easy enough for the concerned developer who to check if the entered network address does actually have all of its host bits set to zero. It is not my experience that this behavior is desired so often that having the network classes behave as they do now leads to a great deal of confusion.
I think we're in a painful middle ground now - we should either go back to the idea of a single class (per protocol), or make the distinctions clear (networks are containers and addresses are singletons). Personally, I think I would be happy with a single class (but I suspect that's just my laziness speaking). However, I think the structure and discipline of three classes (per protocol) may actually make the concepts easier to understand for non-experts. A particular case in point - if you want to represent a single IP address with netmask (say an interface), you use a Network class, not an Address class. And the .network attribute returns a Address class! The reason I suggest having the Network class assert that masked bits be zero is two-fold: * it ensures the correct class is being used for the job * it ensures application-user errors are detected as early as possible I also suggest the AddressWithMask classes not have any network/container behaviours for a similar reason. If the developer needs these, the .network attribute is only a lookup away. -- Andrew McNamara, Senior Developer, Object Craft http://www.object-craft.com.au/
On Wed, Sep 16, 2009 at 6:32 PM, Andrew McNamara <andrewm@object-craft.com.au> wrote:
This proposal actually leads to 6 entities (3 for IPv4 and 3 for IPv6).
Yes, I know - I was just trying to keep to the point.
It's still unclear to me what is gained by pulling AddressWithMask functionality out of the current network classes. It's easy enough for the concerned developer who to check if the entered network address does actually have all of its host bits set to zero. It is not my experience that this behavior is desired so often that having the network classes behave as they do now leads to a great deal of confusion.
I think we're in a painful middle ground now - we should either go back to the idea of a single class (per protocol), or make the distinctions clear (networks are containers and addresses are singletons).
Personally, I think I would be happy with a single class (but I suspect that's just my laziness speaking). However, I think the structure and discipline of three classes (per protocol) may actually make the concepts easier to understand for non-experts.
I think this is where we disagree. I don't think the added complexity does make it any easier to understand.
A particular case in point - if you want to represent a single IP address with netmask (say an interface), you use a Network class, not an Address class. And the .network attribute returns a Address class!
Right, and I don't see where the confusion lies. You have an address + netmask. ergo, you have a Network object. The single address that defines the base address (most commonly referred to as the network address) is an Address object. there is no netmask associated with that single address, ergo, it's an Address object.
The reason I suggest having the Network class assert that masked bits be zero is two-fold:
* it ensures the correct class is being used for the job * it ensures application-user errors are detected as early as possible
I also suggest the AddressWithMask classes not have any network/container behaviours for a similar reason. If the developer needs these, the .network attribute is only a lookup away.
the problem I have with this approach is that it seems like a long way to go for a shortcut (of checking if addr.ip != addr.network: raise Error). Cheers, /peter
-- Andrew McNamara, Senior Developer, Object Craft http://www.object-craft.com.au/ _______________________________________________ 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:
I don't see where the confusion lies. You have an address + netmask. ergo, you have a Network object. The single address that defines the base address (most commonly referred to as the network address) is an Address object. there is no netmask associated with that single address, ergo, it's an Address object.
But if I understand correctly, you *don't* have a network, you have something representing a particular host address within a network, plus information that lets you deduce the network to which it belongs. So calling the object a 'Network' is a misnomer. What's more, I don't see the point of having a 'network' attribute without a mask, because the zero address of a network on its own doesn't define the network. You need the zero address plus a mask to do that. I'm not sure what usefulness the zero address on its own has, but if it's considered useful enough to have an attribute for it, calling it something like 'base_address' would be less confusing. -- Greg
On Wed, Sep 16, 2009 at 7:48 PM, Greg Ewing <greg.ewing@canterbury.ac.nz> wrote:
Peter Moody wrote:
I don't see where the confusion lies. You have an address + netmask. ergo, you have a Network object. The single address that defines the base address (most commonly referred to as the network address) is an Address object. there is no netmask associated with that single address, ergo, it's an Address object.
But if I understand correctly, you *don't* have a network, you have something representing a particular host address within a network, plus information that lets you deduce the network to which it belongs. So calling the object a 'Network' is a misnomer.
What's more, I don't see the point of having a 'network' attribute without a mask, because the zero address of a network on its own doesn't define the network. You need the zero address plus a mask to do that.
I'm not sure what usefulness the zero address on its own has, but if it's considered useful enough to have an attribute for it, calling it something like 'base_address' would be less confusing.
the address with all of the hosts bits masked to zero is most commonly referred to as the network address. same as the address with all of the host bits set to one is called the broadcast address. calling it something like base_address or min_address will cause quite a bit more confusion.
-- Greg _______________________________________________ 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 <peter <at> hda3.com> writes:
the address with all of the hosts bits masked to zero is most commonly referred to as the network address. same as the address with all of the host bits set to one is called the broadcast address. calling it something like base_address or min_address will cause quite a bit more confusion.
Quite a bit less IMO. I'm not a network specialist, but the "network address" of a network sounds quite vague to me, while things like "lower_bound", "first", "first_address", "firstip" are immediately understandable and non-ambiguous.
Antoine Pitrou wrote:
Peter Moody <peter <at> hda3.com> writes:
the address with all of the hosts bits masked to zero is most commonly referred to as the network address. same as the address with all of the host bits set to one is called the broadcast address. calling it something like base_address or min_address will cause quite a bit more confusion.
Quite a bit less IMO. I'm not a network specialist, but the "network address"
Nah, network address is perfectly explicit - it's what you get when you bitwise and any host within that network with the netmask. Where it becomes confusing is that we have a property called "network" that returns an IPAddress object rather than an IPNetwork object. People that are network specialists would grasp that fairly easily, but we try to design standard library APIs so that they're novice friendly as well. And the above situation isn't novice friendly. To be honest, given the indexing behaviour, I'm -1 on the idea of giving the network address or broadcast address attribute names *at all*. Consider: network_address = my_net[0] broadcast_address = my_net[-1] The only way the network address could match the number of characters in the indexing method is if you just called it the network id (i.e. my_net.id). For the broadcast address, there is no name that even comes close to matching the indexing approach for brevity. And since IPNetwork is a container for IPAddress instances, the indexing approach means there is zero ambiguity regarding the return type. Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia ---------------------------------------------------------------
Nick Coghlan wrote:
To be honest, given the indexing behaviour, I'm -1 on the idea of giving the network address or broadcast address attribute names *at all*. Consider:
network_address = my_net[0] broadcast_address = my_net[-1]
My only concern with this is a possible performance issue with v6 networks. Would this be implemented such that [-1] doesn't need to iterate through the (possibly large) address space of a v6 network? I think it could (and would) be implemented efficiently, so I'm +1 on not giving these names, but adding this "recipe" to the documentation instead. Eric.
On Thu, Sep 17, 2009 at 6:25 AM, Eric Smith <eric@trueblade.com> wrote:
Nick Coghlan wrote:
To be honest, given the indexing behaviour, I'm -1 on the idea of giving the network address or broadcast address attribute names *at all*. Consider:
network_address = my_net[0] broadcast_address = my_net[-1]
My only concern with this is a possible performance issue with v6 networks. Would this be implemented such that [-1] doesn't need to iterate through the (possibly large) address space of a v6 network?
I think it could (and would) be implemented efficiently, so I'm +1 on not giving these names, but adding this "recipe" to the documentation instead.
indexing is plenty efficient, but the problem is that these names for these attributes are common to the point of causing confusion if they're omitted. Cheers, /peter
Eric.
_______________________________________________ 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:
indexing is plenty efficient, but the problem is that these names for these attributes are common to the point of causing confusion if they're omitted.
After thinking about it some more, I'm okay with names for [-1] and [0]. I like .broadcast, and I can live with .network (although it's confusing, since in my view it should return an address, not a network). Eric.
Eric Smith wrote:
Peter Moody wrote:
indexing is plenty efficient, but the problem is that these names for these attributes are common to the point of causing confusion if they're omitted.
After thinking about it some more, I'm okay with names for [-1] and [0]. I like .broadcast, and I can live with .network (although it's confusing, since in my view it should return an address, not a network).
And in fact *does* return an Address - the same address that my_net[0] returns. Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia ---------------------------------------------------------------
On 18Sep2009 07:48, Nick Coghlan <ncoghlan@gmail.com> wrote: | Eric Smith wrote: | > Peter Moody wrote: | >> indexing is plenty efficient, but the problem is that these names for | >> these attributes are common to the point of causing confusion if | >> they're omitted. | > | > After thinking about it some more, I'm okay with names for [-1] and [0]. | > I like .broadcast, and I can live with .network (although it's | > confusing, since in my view it should return an address, not a network). | | And in fact *does* return an Address - the same address that my_net[0] | returns. Yes, I think Eric was complaining about the name being "network", since we have Network objects and this isn't one. -- Cameron Simpson <cs@zip.com.au> DoD#743 http://www.cskk.ezoshosting.com/cs/
Cameron Simpson wrote:
On 18Sep2009 07:48, Nick Coghlan <ncoghlan@gmail.com> wrote: | Eric Smith wrote: | > Peter Moody wrote: | >> indexing is plenty efficient, but the problem is that these names for | >> these attributes are common to the point of causing confusion if | >> they're omitted. | > | > After thinking about it some more, I'm okay with names for [-1] and [0]. | > I like .broadcast, and I can live with .network (although it's | > confusing, since in my view it should return an address, not a network). | | And in fact *does* return an Address - the same address that my_net[0] | returns.
Yes, I think Eric was complaining about the name being "network", since we have Network objects and this isn't one.
Right. thing_commonly_referred_to_as_network_but_is_an_address.
Eric Smith wrote:
My only concern with this is a possible performance issue with v6 networks. Would this be implemented such that [-1] doesn't need to iterate through the (possibly large) address space of a v6 network?
I'm not familiar with v6, but if netmasks work the same way as they do in v4, then there's no need to iterate over anything -- it's just a matter of turning on all the low bits of the address. -- Greg
On Thu, 17 Sep 2009 10:40:47 pm Nick Coghlan wrote:
Antoine Pitrou wrote:
Peter Moody <peter <at> hda3.com> writes:
the address with all of the hosts bits masked to zero is most commonly referred to as the network address. same as the address with all of the host bits set to one is called the broadcast address. calling it something like base_address or min_address will cause quite a bit more confusion.
Quite a bit less IMO. I'm not a network specialist, but the "network address"
Nah, network address is perfectly explicit - it's what you get when you bitwise and any host within that network with the netmask.
[soapbox] I really wish people would stop misusing the word "explicit" to mean (apparently) "I know how this is commonly defined". To a non-specialist, "the network address" is ambiguous. There are many addresses in a network, and none of them are the entire network. It's like saying, given a list [2, 4, 8, 12], what's "the list item"? If network specialists have a convention of calling hostadd&netmask "the network address", that's fine. It's jargon which seems illogical to me, but if it's useful and in common use, specialists will expect us to support it. But it's not explicit, it's a definition.
Where it becomes confusing is that we have a property called "network" that returns an IPAddress object rather than an IPNetwork object.
People that are network specialists would grasp that fairly easily, but we try to design standard library APIs so that they're novice friendly as well. And the above situation isn't novice friendly.
+1000 on this!
To be honest, given the indexing behaviour, I'm -1 on the idea of giving the network address or broadcast address attribute names *at all*. Consider:
network_address = my_net[0] broadcast_address = my_net[-1]
The only way the network address could match the number of characters in the indexing method is if you just called it the network id (i.e. my_net.id). For the broadcast address, there is no name that even comes close to matching the indexing approach for brevity.
Is brevity so much more important than clarity and discoverability? -- Steven D'Aprano
To a non-specialist, "the network address" is ambiguous. There are many addresses in a network, and none of them are the entire network. It's like saying, given a list [2, 4, 8, 12], what's "the list item"?
A "network address" is an IP address and mask, but I understand your confusion - we're mixing terminology from disperate domains. In my postings, I have tried to refer to Network (a containter) and Address (an item). -- Andrew McNamara, Senior Developer, Object Craft http://www.object-craft.com.au/
On Fri, 18 Sep 2009 at 11:04, Andrew McNamara wrote:
[attribution lost; apparently Steven D'Aprano given the CC]
To a non-specialist, "the network address" is ambiguous. There are many addresses in a network, and none of them are the entire network. It's like saying, given a list [2, 4, 8, 12], what's "the list item"?
A "network address" is an IP address and mask, but I understand your confusion - we're mixing terminology from disperate domains. In my postings, I have tried to refer to Network (a containter) and Address (an item).
Apparently not, in many people's vocabulary. The 'network address' is used to designate the IP address whose bits corresponding to the one bits in the mask have been set to zero (ie: the first IP address in the network range). It is interesting how this item seems to lead to the greatest amount of confusion on everyone's part, and I'm guessing it is because the common terminology and usage blurs the line between addresses and networks. And that's what we are trying to make clear(er) through a well structured API. --David
2009/9/18 R. David Murray <rdmurray@bitdance.com>:
On Fri, 18 Sep 2009 at 11:04, Andrew McNamara wrote:
[attribution lost; apparently Steven D'Aprano given the CC]
To a non-specialist, "the network address" is ambiguous. There are many addresses in a network, and none of them are the entire network. It's like saying, given a list [2, 4, 8, 12], what's "the list item"?
A "network address" is an IP address and mask, but I understand your confusion - we're mixing terminology from disperate domains. In my postings, I have tried to refer to Network (a containter) and Address (an item).
Apparently not, in many people's vocabulary. The 'network address' is used to designate the IP address whose bits corresponding to the one bits in the mask have been set to zero (ie: the first IP address in the network range).
It is interesting how this item seems to lead to the greatest amount of confusion on everyone's part, and I'm guessing it is because the common terminology and usage blurs the line between addresses and networks. And that's what we are trying to make clear(er) through a well structured API.
How non-expert do you want to get? My immediate reaction is that the network address of my PC is 157.215.187.94 - it's what comes up ad "IP address" when I type ipconfig. I understand why that's "wrong", and I see why the definitions above are "better", but that doesn't affect my instinct. Suggestion - just don't use the term "network address" anywhere in the library, the PEP, or its documentation. The term seems too loaded with contradictory meanings to be useful. If the concept behind it (one of the many concepts - among our concepts...) is useful, then maybe coin a new term specific to the module. Paul.
On Fri, 18 Sep 2009 11:04:46 am Andrew McNamara wrote:
To a non-specialist, "the network address" is ambiguous. There are many addresses in a network, and none of them are the entire network. It's like saying, given a list [2, 4, 8, 12], what's "the list item"?
A "network address" is an IP address and mask, but I understand your confusion - we're mixing terminology from disperate domains. In my postings, I have tried to refer to Network (a containter) and Address (an item).
So to clarify, how many different things which need to be handled are there? Items: 1 IP address -- a 32 bit (IPv4) or 128 bit (IPv6) number 2 Netmask -- a bit mask of the form 111..100..0 3 Network address -- the lowest address in a network, and equal to (defined by?) the bitwise-AND of any address in the network with the network's netmask 4 Host address -- the part of the IP address that is not masked by the netmask 5 Broadcast address -- the highest address in a IPv4 network Containers: 6 Network -- a range of IP address Have I missed anything or got anything wrong? -- Steven D'Aprano
On Fri, 18 Sep 2009 11:04:46 am Andrew McNamara wrote:
To a non-specialist, "the network address" is ambiguous. There are many addresses in a network, and none of them are the entire network. It's like saying, given a list [2, 4, 8, 12], what's "the list item"?
A "network address" is an IP address and mask, but I understand your confusion - we're mixing terminology from disperate domains. In my postings, I have tried to refer to Network (a containter) and Address (an item).
So to clarify, how many different things which need to be handled are there?
Items: 1 IP address -- a 32 bit (IPv4) or 128 bit (IPv6) number
Yes.
2 Netmask -- a bit mask of the form 111..100..0
I don't think there's much to be gained by exposing a Netmask object, although other objects might have a .netmask property returning an IPAddress instance. Where we expose a netmask, it should be as an Address instance (or maybe a subclass with additional restrictions).
3 Network address -- the lowest address in a network, and equal to (defined by?) the bitwise-AND of any address in the network with the network's netmask
This idea of a "network address" being simply an IP address is in error - a network address was always an address and a mask, however in the days prior to CIDR, the mask was implicitly specified by the class of the network.
4 Host address -- the part of the IP address that is not masked by the netmask
Well, yes, but I don't think we need an entity representing that.
5 Broadcast address -- the highest address in a IPv4 network
Yes, but again, we don't need an entity - as with the netmask, when exposed, it should just be an Address instance (or subclass thereof).
Containers: 6 Network -- a range of IP address
Yes, although not an arbitrary or discontinuous range of address. Really, I think we just need two entities (per protocol): Address (& maybe AddressWithMask) * If no mask is specified, this is just the IP address. * If a mask is specified, then it gains a .network property returning a Network instance. It probably should also have a .netmask property containing an Address instance. Network * Has an IP address with netmask * for consistency's sake, masked address bits are not allowed * behaves like a read-only container wrt Addresses So, you want to represent an interface on your host:
if_addr = IPv4Address('10.0.0.1/24')
from this, you could get:
if_addr.address IPv4Address('10.0.0.1') if_addr.netmask IPv4Address('255.255.255.0') if_addr.broadcast IPv4Address('10.0.0.255') if_addr.network IPV4Network('10.0.0.0/24')
you might also have an address for the default gateway:
router_addr = IPv4Address('10.0.0.254/24') router_addr in if_addr.network True
or:
router_addr = IPv4Address('10.0.0.254') router_addr in if_addr.network True
Or maybe you've subneted your LAN:
IPV4Network('10.0.0.0/24') in IPv4Network('10.0.0.0/8') True IPV4Network('10.0.1.0/24') in IPv4Network('10.0.0.0/8') True
but:
IPV4Network('10.0.0.0/8') in IPv4Network('10.0.0.0/24') False
This suggests the natural behaviour if the Address mask doesn't fit in the network:
IPv4Address('10.0.0.254/8') in IPv4Network('10.0.0.0/24') False
-- Andrew McNamara, Senior Developer, Object Craft http://www.object-craft.com.au/
On Wed, 16 Sep 2009 at 20:26, Peter Moody wrote:
On Wed, Sep 16, 2009 at 7:48 PM, Greg Ewing <greg.ewing@canterbury.ac.nz> wrote:
I'm not sure what usefulness the zero address on its own has, but if it's considered useful enough to have an attribute for it, calling it something like 'base_address' would be less confusing.
the address with all of the hosts bits masked to zero is most commonly referred to as the network address. same as the address with all of the host bits set to one is called the broadcast address. calling it something like base_address or min_address will cause quite a bit more confusion.
If 'network address' is the most common designation for this number (and it may well be), then 'network.address' and 'network.broadcast' would seem to be the best choices for names. But there is definitely an attraction to the idea (I think it was Nick's?) of dropping these attributes entirely and just using indexing to get the addresses. That will make perfect sense to network professionals, and by putting appropriate words in the documentation will educate people new to IP addressing concepts. The advantage is that it is completely unambiguous: the network address really is the first address in the network range, and the broadcast really is the last, in common usage. Exceptional cases can then be handled by custom subclasses, without having someone who has to handle weird broadcast addresses (for example) submitting a bug request to make '.broadcast' settable. --David
On Thu, Sep 17, 2009 at 3:27 PM, Greg Ewing <greg.ewing@canterbury.ac.nz> wrote:
Peter Moody wrote:
the address with all of the hosts bits masked to zero is most commonly referred to as the network address.
Then call the attribute 'network_address', not just 'network'.
from an earlier email: Again, the same error-catching functionality can be obtained through an option to the constructor. network and broadcast attributes can be renamed to .\1_address to alleviate confusion as well.
-- Greg _______________________________________________ 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
I think we're in a painful middle ground now - we should either go back to the idea of a single class (per protocol), or make the distinctions clear (networks are containers and addresses are singletons).
Personally, I think I would be happy with a single class (but I suspect that's just my laziness speaking). However, I think the structure and discipline of three classes (per protocol) may actually make the concepts easier to understand for non-experts.
I think this is where we disagree. I don't think the added complexity does make it any easier to understand.
I argue that we're not actually adding any complexity: yes, we add a class (per protocol), but we then merely relocate functionality to clarify the intended use of the classes.
A particular case in point - if you want to represent a single IP address with netmask (say an interface), you use a Network class, not an Address class. And the .network attribute returns a Address class!
Right, and I don't see where the confusion lies.
I suggest you are too close to the implementation to be surprised by it. 8-)
You have an address + netmask. ergo, you have a Network object.
In a common use case, however, this instance will not represent a network at all, but an address. It will have container-like behaviour, but it should not (this is a property of networks, not addresses). So the instance will be misnamed and have behaviours that are, at best, misleading.
The single address that defines the base address (most commonly referred to as the network address) is an Address object. there is no netmask associated with that single address, ergo, it's an Address object.
I would argue that a Network never has a single address - by definition, it has two or more nodes. A .network attribute should return a Network instance. If you want the base address, this probably should be called .base_address or just .address (to parallel the .netmask attribute).
The reason I suggest having the Network class assert that masked bits be zero is two-fold:
* it ensures the correct class is being used for the job * it ensures application-user errors are detected as early as possible
I also suggest the AddressWithMask classes not have any network/container behaviours for a similar reason. If the developer needs these, the .network attribute is only a lookup away.
the problem I have with this approach is that it seems like a long way to go for a shortcut (of checking if addr.ip != addr.network: raise Error).
This isn't about shortcuts, but about correctness... having the Network object represent a network, and having Address objects represent end-points, and having errors discovered as early as possible. What I'm arguing here is that singletons should not simultaneously be containers - it's not pythonic, and it leads to ambiguity. The underlying IP concepts don't require it either: an IP address is a singleton, a network is a container, and there is no overlap. Yes, an address may be a member of a network, and having a reference to that network on the address object is valuable, but the address should not behave like a network. -- Andrew McNamara, Senior Developer, Object Craft http://www.object-craft.com.au/
On Wed, Sep 16, 2009 at 8:21 PM, Andrew McNamara <andrewm@object-craft.com.au> wrote:
I think we're in a painful middle ground now - we should either go back to the idea of a single class (per protocol), or make the distinctions clear (networks are containers and addresses are singletons).
Personally, I think I would be happy with a single class (but I suspect that's just my laziness speaking). However, I think the structure and discipline of three classes (per protocol) may actually make the concepts easier to understand for non-experts.
I think this is where we disagree. I don't think the added complexity does make it any easier to understand.
I argue that we're not actually adding any complexity: yes, we add a class (per protocol), but we then merely relocate functionality to clarify the intended use of the classes.
And I argue the moving this functionality to new classes (and adding new restrictions to existing classes) doesn't buy anything in the way of overall functionality of the module or a developer's ability to comprehend intended uses.
A particular case in point - if you want to represent a single IP address with netmask (say an interface), you use a Network class, not an Address class. And the .network attribute returns a Address class!
Right, and I don't see where the confusion lies.
I suggest you are too close to the implementation to be surprised by it. 8-)
touche :)
You have an address + netmask. ergo, you have a Network object.
In a common use case, however, this instance will not represent a network at all, but an address. It will have container-like behaviour, but it should not (this is a property of networks, not addresses). So the instance will be misnamed and have behaviours that are, at best, misleading.
The single address that defines the base address (most commonly referred to as the network address) is an Address object. there is no netmask associated with that single address, ergo, it's an Address object.
I would argue that a Network never has a single address - by definition, it has two or more nodes. A .network attribute should return a Network instance. If you want the base address, this probably should be called .base_address or just .address (to parallel the .netmask attribute).
.network is shorthand for network address. are .network_address and .broadcast_address less confusing? I have to say, though, .network/.broadcast are fairly common (IPy uses .net, netaddr and ipv4 use, IIRC .network...)
The reason I suggest having the Network class assert that masked bits be zero is two-fold:
* it ensures the correct class is being used for the job * it ensures application-user errors are detected as early as possible
I also suggest the AddressWithMask classes not have any network/container behaviours for a similar reason. If the developer needs these, the .network attribute is only a lookup away.
the problem I have with this approach is that it seems like a long way to go for a shortcut (of checking if addr.ip != addr.network: raise Error).
This isn't about shortcuts, but about correctness... having the Network object represent a network, and having Address objects represent end-points, and having errors discovered as early as possible.
Then what I don't see is the purpose of your network-only-network-object. essentially identical functionality can be obtained with the module as is w/o the added complexity of new classes. Cheers, /peter
What I'm arguing here is that singletons should not simultaneously be containers - it's not pythonic, and it leads to ambiguity. The underlying IP concepts don't require it either: an IP address is a singleton, a network is a container, and there is no overlap. Yes, an address may be a member of a network, and having a reference to that network on the address object is valuable, but the address should not behave like a network.
-- Andrew McNamara, Senior Developer, Object Craft http://www.object-craft.com.au/
On Wed, Sep 16, 2009 at 8:36 PM, Peter Moody <peter@hda3.com> wrote:
On Wed, Sep 16, 2009 at 8:21 PM, Andrew McNamara <andrewm@object-craft.com.au> wrote:
I think we're in a painful middle ground now - we should either go back to the idea of a single class (per protocol), or make the distinctions clear (networks are containers and addresses are singletons).
Personally, I think I would be happy with a single class (but I suspect that's just my laziness speaking). However, I think the structure and discipline of three classes (per protocol) may actually make the concepts easier to understand for non-experts.
I think this is where we disagree. I don't think the added complexity does make it any easier to understand.
I argue that we're not actually adding any complexity: yes, we add a class (per protocol), but we then merely relocate functionality to clarify the intended use of the classes.
And I argue the moving this functionality to new classes (and adding new restrictions to existing classes) doesn't buy anything in the way of overall functionality of the module or a developer's ability to comprehend intended uses.
A particular case in point - if you want to represent a single IP address with netmask (say an interface), you use a Network class, not an Address class. And the .network attribute returns a Address class!
Right, and I don't see where the confusion lies.
I suggest you are too close to the implementation to be surprised by it. 8-)
touche :)
You have an address + netmask. ergo, you have a Network object.
In a common use case, however, this instance will not represent a network at all, but an address. It will have container-like behaviour, but it should not (this is a property of networks, not addresses). So the instance will be misnamed and have behaviours that are, at best, misleading.
The single address that defines the base address (most commonly referred to as the network address) is an Address object. there is no netmask associated with that single address, ergo, it's an Address object.
I would argue that a Network never has a single address - by definition, it has two or more nodes. A .network attribute should return a Network instance. If you want the base address, this probably should be called .base_address or just .address (to parallel the .netmask attribute).
.network is shorthand for network address. are .network_address and .broadcast_address less confusing? I have to say, though, .network/.broadcast are fairly common (IPy uses .net, netaddr and ipv4 use, IIRC .network...)
The reason I suggest having the Network class assert that masked bits be zero is two-fold:
* it ensures the correct class is being used for the job * it ensures application-user errors are detected as early as possible
I also suggest the AddressWithMask classes not have any network/container behaviours for a similar reason. If the developer needs these, the .network attribute is only a lookup away.
the problem I have with this approach is that it seems like a long way to go for a shortcut (of checking if addr.ip != addr.network: raise Error).
This isn't about shortcuts, but about correctness... having the Network object represent a network, and having Address objects represent end-points, and having errors discovered as early as possible.
Then what I don't see is the purpose of your network-only-network-object. essentially identical functionality can be obtained with the module as is w/o the added complexity of new classes.
Since you mentioned correctness; it seems like we're coming back to an option to the IPv?Network().__init__ methods which strictly checks for host bits being masked to zero. this provides, I think, the functionality/error checking you're looking for w/o the need for new classes. Cheers, /peter
Cheers, /peter
What I'm arguing here is that singletons should not simultaneously be containers - it's not pythonic, and it leads to ambiguity. The underlying IP concepts don't require it either: an IP address is a singleton, a network is a container, and there is no overlap. Yes, an address may be a member of a network, and having a reference to that network on the address object is valuable, but the address should not behave like a network.
-- Andrew McNamara, Senior Developer, Object Craft http://www.object-craft.com.au/
Peter Moody wrote:
On Wed, Sep 16, 2009 at 8:21 PM, Andrew McNamara <andrewm@object-craft.com.au> wrote:
I think we're in a painful middle ground now - we should either go back to the idea of a single class (per protocol), or make the distinctions clear (networks are containers and addresses are singletons).
Personally, I think I would be happy with a single class (but I suspect that's just my laziness speaking). However, I think the structure and discipline of three classes (per protocol) may actually make the concepts easier to understand for non-experts. I think this is where we disagree. I don't think the added complexity does make it any easier to understand. I argue that we're not actually adding any complexity: yes, we add a class (per protocol), but we then merely relocate functionality to clarify the intended use of the classes.
And I argue the moving this functionality to new classes (and adding new restrictions to existing classes) doesn't buy anything in the way of overall functionality of the module or a developer's ability to comprehend intended uses.
Speaking as the originator of this thread of discourse, the lack of a 3rd class was exactly the source of my confusion and my inability to communicate my confusion to everyone. I clearly did not understand the intended uses of the IPNetwork type because it was capable of playing two roles that are decidedly different conceptually. So, I must respectfully disagree with you.
You have an address + netmask. ergo, you have a Network object. In a common use case, however, this instance will not represent a network at all, but an address. It will have container-like behaviour, but it should not (this is a property of networks, not addresses). So the instance will be misnamed and have behaviours that are, at best, misleading.
This is exactly the confusion and duality that I struggled with.
This isn't about shortcuts, but about correctness... having the Network object represent a network, and having Address objects represent end-points, and having errors discovered as early as possible.
Then what I don't see is the purpose of your network-only-network-object. essentially identical functionality can be obtained with the module as is w/o the added complexity of new classes.
The purpose is to avoid conflating IPNetwork with an IPAddress that has a mask. If the IPNetwork didn't accept a non-zero host and instead required a developer to use a helper to construct a IPNetwork with a proper address, then there would be less confusion about what exactly a IPNetwork is meant to represent. As it stands, it's purposes is muddled by accepting host addresses too. I am rather indifferent whether there needs to be a IPAddressWithMask type. If that is needed, then it is rather easy to create a type that does that. And, if it is a common pattern, then it could be added to the module later in life. -- Scott Dial scott@scottdial.com scodial@cs.indiana.edu -- Scott Dial scott@scottdial.com scodial@cs.indiana.edu
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Scott Dial wrote:
The purpose is to avoid conflating IPNetwork with an IPAddress that has a mask.
I'm not confused by anything in this discussion except the repeated harping on the (to me imaginary) concept of "address with a mask". Conceptually: - Addresses don't have masks: they are just 32- (128-) bit integers. - Any given address can belong to a number of networks, based on a given topology. - Masks are also 32- (128-) bit integers, which happen to have the property that their leftmost N bits are all zero and the rest are all one. - One can construct a network from the combination of an address and a mask. Such a network *never* needs to know what the address was before masking. - Networks *do* know their "zero" address, as well as their "last address", and can do "containment" operations on addresses (I'm not clear on the need to do such operations on other networks, rather than just using their zero addresses). At the API level, it is convenient to represent the combination (address, mask) as a single string (e.g., '192.168.1.0/24'): parsing that string should return a network, not an address. Let's keep the "parsing human readable / writable strings" part separate from the clear conceptual map.
If the IPNetwork didn't accept a non-zero host and instead required a developer to use a helper to construct a IPNetwork with a proper address, then there would be less confusion about what exactly a IPNetwork is meant to represent. As it stands, it's purposes is muddled by accepting host addresses too.
I can't imagine why it would be useful to try to infer a network from an address: "In the face of ambiguity, refuse the temptation to guess."
I am rather indifferent whether there needs to be a IPAddressWithMask type. If that is needed, then it is rather easy to create a type that does that. And, if it is a common pattern, then it could be added to the module later in life.
Agreed. Tres. - -- =================================================================== Tres Seaver +1 540-429-0999 tseaver@palladion.com Palladion Software "Excellence by Design" http://palladion.com -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.6 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org iD8DBQFKsbeU+gerLs4ltQ4RAlG0AJ9ZvhuXHsTL2hheW/vlzeMmArs5rgCeLDLS eKWSAdkdv++umepu+nK0/7I= =N7ej -----END PGP SIGNATURE-----
- Masks are also 32- (128-) bit integers, which happen to have the property that their leftmost N bits are all zero and the rest are all one.
As a side note, I would be in favor of dropping the concept of a mask from the library, and only support a prefix length. IPv6 doesn't support masks at all, and even for IPv4, I think there are conventions (if not RFCs) against using them in a way that does not correspond to a prefix length. Regards, Martin
On Sun, 27 Sep 2009 03:44:45 am Martin v. Löwis wrote:
- Masks are also 32- (128-) bit integers, which happen to have the property that their leftmost N bits are all zero and the rest are all one.
As a side note, I would be in favor of dropping the concept of a mask from the library, and only support a prefix length.
-1
IPv6 doesn't support masks at all, and even for IPv4, I think there are conventions (if not RFCs) against using them in a way that does not correspond to a prefix length.
Then the module should only support netmasks of the form (say) '255.255.255.224' (equivalent to "/27"), and reject those like "255.3.255.255". It currently accepts them. Many applications still display netmasks in dot-quad form, and I would be terribly annoyed if I had to count the bits myself before passing it to IPv4Address. -- Steven D'Aprano
As a side note, I would be in favor of dropping the concept of a mask from the library, and only support a prefix length.
-1
IPv6 doesn't support masks at all, and even for IPv4, I think there are conventions (if not RFCs) against using them in a way that does not correspond to a prefix length.
Then the module should only support netmasks of the form (say) '255.255.255.224' (equivalent to "/27"), and reject those like "255.3.255.255". It currently accepts them.
Many applications still display netmasks in dot-quad form, and I would be terribly annoyed if I had to count the bits myself before passing it to IPv4Address.
I wouldn't ask for that: it should certainly be possible to supply masks. However, I would want to reject masks that don't correspond to a prefix, and have only the prefix length in the internal representation. Regards, Martin
Dave M. On 27 Sep 2009, at 07:56, "Martin v. Löwis" <martin@v.loewis.de> wrote:
As a side note, I would be in favor of dropping the concept of a mask from the library, and only support a prefix length.
-1
IPv6 doesn't support masks at all, and even for IPv4, I think there are conventions (if not RFCs) against using them in a way that does not correspond to a prefix length.
Then the module should only support netmasks of the form (say) '255.255.255.224' (equivalent to "/27"), and reject those like "255.3.255.255". It currently accepts them.
Many applications still display netmasks in dot-quad form, and I would be terribly annoyed if I had to count the bits myself before passing it to IPv4Address.
I wouldn't ask for that: it should certainly be possible to supply masks. However, I would want to reject masks that don't correspond to a prefix, and have only the prefix length in the internal representation.
+1 on rejection of netmasks without direct CIDR prefix equivalents. AFAIK Cisco routers accept them but I don't see how they would be useful in practice (unless someone can demonstrate their need for this).
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/drkjam%40gmail.com
On Sun, 27 Sep 2009 at 10:06, David Moss wrote:
On 27 Sep 2009, at 07:56, "Martin v. Löwis" <martin@v.loewis.de> wrote:
I wouldn't ask for that: it should certainly be possible to supply masks. However, I would want to reject masks that don't correspond to a prefix, and have only the prefix length in the internal representation.
+1 on rejection of netmasks without direct CIDR prefix equivalents. AFAIK Cisco routers accept them but I don't see how they would be useful in practice (unless someone can demonstrate their need for this).
Several years ago I ran into a network with a non-CIDR netmask. This was in the early days of CIDR, and I hope that that network is no longer configured that way.... A little googling produced this hit: http://tools.ietf.org/wg/mip4/draft-ietf-mip4-nemo-v4-base/draft-ietf-mip4-n... which while not a standard itself clearly believes that non-contiguous netmasks are valid, and is dated 2008. Earlier RFCs (950 and 1219) give them as valid but discouraged. The linux stack (or at least the ifconfig command on my system) does not appear to support non-contiguous netmasks. From a brief search on Cisco's site it looks like Cisco only partially supports non-contiguous masks (you can use them in wildmasks in access lists, but not in subnet masks on interfaces). (I just tried setting a non-contiguous netmask on an interface on one of my Ciscos, and it gave me a 'bad mask' error message.) I think support for non-contiguous netmasks could be safely omitted, but it would mean the module did not fully support the standards, which should be noted in the docs (and why). --David
On Mon, Sep 28, 2009 at 9:35 AM, R. David Murray <rdmurray@bitdance.com>wrote:
A little googling produced this hit:
http://tools.ietf.org/wg/mip4/draft-ietf-mip4-nemo-v4-base/draft-ietf-mip4-n...
which while not a standard itself clearly believes that non-contiguous netmasks are valid, and is dated 2008. Earlier RFCs (950 and 1219) give them as valid but discouraged.
That's a draft for RFC 5177. In the RFC, all references to non-contiguous subnets have been removed. http://tools.ietf.org/html/rfc5177 -- Daniel Stutzbach, Ph.D. President, Stutzbach Enterprises, LLC <http://stutzbachenterprises.com>
I argue that we're not actually adding any complexity: yes, we add a class (per protocol), but we then merely relocate functionality to clarify the intended use of the classes.
And I argue the moving this functionality to new classes (and adding new restrictions to existing classes) doesn't buy anything in the way of overall functionality of the module or a developer's ability to comprehend intended uses.
It's mostly just minor refactoring and renaming, which I think makes things clearer, although I agree this is merely an opinion. I would be interest to hear what others think. To summarise: * an address is a singleton (a network endpoint), with no container behaviour. It may optionally reference it's network (via the .network attribute), .address returns mask-less address. * a network is a container-like object. For consistency, .network should return self and raise an exception if the mask conflicts with the address, .address returns the base address, .mask returns an address object.
I would argue that a Network never has a single address - by definition, it has two or more nodes. A .network attribute should return a Network instance. If you want the base address, this probably should be called .base_address or just .address (to parallel the .netmask attribute).
.network is shorthand for network address. are .network_address and .broadcast_address less confusing? I have to say, though, .network/.broadcast are fairly common (IPy uses .net, netaddr and ipv4 use, IIRC .network...)
Yes, I understand your motivation, but I still think it's going to be more confusing the way you have it.
This isn't about shortcuts, but about correctness... having the Network object represent a network, and having Address objects represent end-points, and having errors discovered as early as possible.
Then what I don't see is the purpose of your network-only-network-object. essentially identical functionality can be obtained with the module as is w/o the added complexity of new classes.
Certainly, I'm not talking about adding functionality. What I am suggesting is that if we wish to have a distinction between networks and addresses, then that distinction should be clear and strong, such that the choice of which to use is obvious, and if the wrong one is used, the error is discovered as early as possible. As the module stands, we have a pair of address-without-mask classes called *Address, and a pair of address-with-mask classes called *Network. So, sometimes when you want to record an *address* you use a class called Network, and that class comes with a behaviours that make no sense in the context of a singleton network end-point (it can't "contain" other addresses, although it's .network can). Sorry if I sound like a cracked record - these are subtle concepts, and my ability to explain what I mean is less than is needed, but we'll get there in the end. -- Andrew McNamara, Senior Developer, Object Craft http://www.object-craft.com.au/
Andrew McNamara writes:
As the module stands, we have a pair of address-without-mask classes called *Address, and a pair of address-with-mask classes called *Network. So, sometimes when you want to record an *address* you use a class called Network, and that class comes with a behaviours that make no sense in the context of a singleton network end-point (it can't "contain" other addresses, although it's .network can).
I'm going to consistently use "address" to mean a singleton and "network" to mean a container in the following. I still don't see why an address-with-mask is useful, except that the network is deducible as {'network': address & mask, 'mask': mask}. Is there *any* other way you would *ever* use that? It seems to me that for some purposes (implementing dig(1), for example), an IPv4Address can contain only the address (ie, a 32-bit integer) as a data attribute, and (with methods for using that attribute) that is the minimal implementation of IPv4Address. However, there are other cases (eg, routing) where it's useful to associate an address with its network, and I don't see much harm in doing so by adding a 'network' attribute to the base class IPv4Address, since addresses are hardly useful except in the context of networks. Of course that attribute is often going to be None (eg, in implementing dig(1) the remote nameserver is unlikely to tell you the netmask). However, when iterating over an IPv4Network, the iterator can automatically fill in the 'network' attribute, and that's fairly cheap. While to me neither the 'network' attribute nor the iterator behavior just described seems amazing useful in the base classes, it seems to me that precisely those behaviors will be reinvented over and over again for derived classes. Furthermore they are natural enough that they won't bother people who don't need them. (That's despite at least one person (IIRC it was Antoine) firmly saying "an IPv4Address should contain exactly one 32-bit int, no more, no less", so I could be wrong.) It seems to me that the only good reason for not having a 'network' attribute that contains an IPv4Network instance or None is efficiency: the space for the attribute and the overhead of filling it in the iterator. I personally can't think of an application that would care (from what I hear, Cisco has no interest in writing its routers' IP stacks in Python, amazingly enough), but in theory ... Finally, I agree that using IPv4Network as address-with-mask is a confusing, undiscoverable abuse. In particular, I think that every time I went a week without using that idiom, I'd get nervous when I saw it again: "Are you *sure* that won't raise an error or silently get the lower bits masked off?! If not now, in the next version?" Obviously all the above applies to IPv6 classes, too.
As the module stands, we have a pair of address-without-mask classes called *Address, and a pair of address-with-mask classes called *Network. So, sometimes when you want to record an *address* you use a class called Network, and that class comes with a behaviours that make no sense in the context of a singleton network end-point (it can't "contain" other addresses, although it's .network can).
I'm going to consistently use "address" to mean a singleton and "network" to mean a container in the following.
Ta. I think it's useful to have a common terminology.
I still don't see why an address-with-mask is useful, except that the network is deducible as {'network': address & mask, 'mask': mask}. Is there *any* other way you would *ever* use that?
It seems to me that for some purposes (implementing dig(1), for example), an IPv4Address can contain only the address (ie, a 32-bit integer) as a data attribute, and (with methods for using that attribute) that is the minimal implementation of IPv4Address.
However, there are other cases (eg, routing) where it's useful to associate an address with its network, and I don't see much harm in doing so by adding a 'network' attribute to the base class IPv4Address, since addresses are hardly useful except in the context of networks. Of course that attribute is often going to be None (eg, in implementing dig(1) the remote nameserver is unlikely to tell you the netmask). However, when iterating over an IPv4Network, the iterator can automatically fill in the 'network' attribute, and that's fairly cheap.
Conceptually, you sometimes need a bare address, and other times, you need an address with an associated network (host interface configs, router configs, etc). By AddressWithMask, I really mean AddressWithEnoughInformationToDeriveNetworkWhenNeeded. Conveniently, IPv4 and IPv6 addressing allows us to derive the network from the host address combined with the netmask - in other words, we don't have to attach a real Network object to Address objects until the user tries to access it, and then we derive it from the address and mask.
While to me neither the 'network' attribute nor the iterator behavior just described seems amazing useful in the base classes, it seems to me that precisely those behaviors will be reinvented over and over again for derived classes. Furthermore they are natural enough that they won't bother people who don't need them. (That's despite at least one person (IIRC it was Antoine) firmly saying "an IPv4Address should contain exactly one 32-bit int, no more, no less", so I could be wrong.)
If you have a .network attribute on an address object, checking if an address is in the same network as another address becomes: addr_a in addr_b.network As the module stands, you write that as: addr_a in addr_b I don't think the intent is as clear with the later.
It seems to me that the only good reason for not having a 'network' attribute that contains an IPv4Network instance or None is efficiency: the space for the attribute and the overhead of filling it in the iterator. I personally can't think of an application that would care (from what I hear, Cisco has no interest in writing its routers' IP stacks in Python, amazingly enough), but in theory ...
The implementation already lazily creates most things like this.
Finally, I agree that using IPv4Network as address-with-mask is a confusing, undiscoverable abuse. In particular, I think that every time I went a week without using that idiom, I'd get nervous when I saw it again: "Are you *sure* that won't raise an error or silently get the lower bits masked off?! If not now, in the next version?"
Yes. -- Andrew McNamara, Senior Developer, Object Craft http://www.object-craft.com.au/
On Thu, 17 Sep 2009 05:15:16 pm Andrew McNamara wrote:
Conceptually, you sometimes need a bare address, and other times, you need an address with an associated network (host interface configs, router configs, etc). By AddressWithMask, I really mean AddressWithEnoughInformationToDeriveNetworkWhenNeeded. Conveniently, IPv4 and IPv6 addressing allows us to derive the network from the host address combined with the netmask - in other words, we don't have to attach a real Network object to Address objects until the user tries to access it, and then we derive it from the address and mask.
To clarify: when you say "derive the network" are you talking about the network (which is a container) or the network address = host_address & netmask (which is not a container)? I think you're referring to the later. If there's need for address+netmask, does it need to be a separate class? Perhaps Address objects could simply have a netmask property, defaulting to None. If you need an "address with mask" object, you create an Address and set the mask: addr = Address(...) addr.netmask = "255.255.255.0" The caller is responsible for ensuring the netmask has been set before trying to use it: network_address = addr & addr.netmask
If you have a .network attribute on an address object, checking if an address is in the same network as another address becomes:
addr_a in addr_b.network
As the module stands, you write that as:
addr_a in addr_b
I don't think the intent is as clear with the later.
I would find the later completely unclear and disturbing -- how can one address contain another address? -- Steven D'Aprano
Conceptually, you sometimes need a bare address, and other times, you need an address with an associated network (host interface configs, router configs, etc). By AddressWithMask, I really mean AddressWithEnoughInformationToDeriveNetworkWhenNeeded. Conveniently, IPv4 and IPv6 addressing allows us to derive the network from the host address combined with the netmask - in other words, we don't have to attach a real Network object to Address objects until the user tries to access it, and then we derive it from the address and mask.
To clarify: when you say "derive the network" are you talking about the network (which is a container) or the network address = host_address & netmask (which is not a container)? I think you're referring to the later.
I mean a Network object which is a container (which, by definition, has a network address + mask).
If there's need for address+netmask, does it need to be a separate class? Perhaps Address objects could simply have a netmask property, defaulting to None. If you need an "address with mask" object, you create an Address and set the mask:
addr = Address(...) addr.netmask = "255.255.255.0"
Greg Ewing suggested this yesterday - I'm neutral on whether it's done this way or as a separate class. The implementation may be somewhat cleaner if it's a separate class, however.
If you have a .network attribute on an address object, checking if an address is in the same network as another address becomes:
addr_a in addr_b.network
As the module stands, you write that as:
addr_a in addr_b
I don't think the intent is as clear with the later.
I would find the later completely unclear and disturbing -- how can one address contain another address?
Yes - that's how it works now, and I can only see it resulting in confusion and bugs for no advantage. -- Andrew McNamara, Senior Developer, Object Craft http://www.object-craft.com.au/
Andrew McNamara writes:
Conceptually, you sometimes need a bare address, and other times, you need an address with an associated network (host interface configs, router configs, etc). By AddressWithMask, I really mean AddressWithEnoughInformationToDeriveNetworkWhenNeeded. Conveniently, IPv4 and IPv6 addressing allows us to derive the network from the host
That's precisely the claim I deny. Yes, you can derive the network *address* from a generic address and a mask. You cannot derive the *network* that way! Eg, suppose in a routing application you have class IPv4NetworkWithGateway(IPv4Network): ... oops. You want *the* IPv4Network instance that has all the gateway info, not just *any* IPv4Network instance that happens to have the same network address and mask. Address + mask is *not* sufficient to derive the desired IPv4Network instance. I grant that sometimes all you really care about is that the network address and the mask match; constructing on the fly would be sufficient. However, many of the applications I can think of attach additional attributes to IPv4Networks, and really do want "the real thing" vs. a constructed imitation.
2009/9/17 Peter Moody <peter@hda3.com>:
On Wed, Sep 16, 2009 at 8:21 PM, Andrew McNamara <andrewm@object-craft.com.au> wrote:
I think we're in a painful middle ground now - we should either go back to the idea of a single class (per protocol), or make the distinctions clear (networks are containers and addresses are singletons).
Personally, I think I would be happy with a single class (but I suspect that's just my laziness speaking). However, I think the structure and discipline of three classes (per protocol) may actually make the concepts easier to understand for non-experts.
I think this is where we disagree. I don't think the added complexity does make it any easier to understand.
I argue that we're not actually adding any complexity: yes, we add a class (per protocol), but we then merely relocate functionality to clarify the intended use of the classes.
And I argue the moving this functionality to new classes (and adding new restrictions to existing classes) doesn't buy anything in the way of overall functionality of the module or a developer's ability to comprehend intended uses.
For what it's worth, Andrew's making the distinction clatified things for *me*. Whether I am the target audience for the module (I'm not a network expert, but on the odd occasion I need to manipulate IP addresses in a program, and if the standard library had a module for doing so, I'd reach for it) is up to someone else to decide, but if I am, then my vote is for 3 classes based on the explanations I've seen so far. I don't see what having fewer classes buys me as the end user. Paul.
Andrew McNamara wrote:
I also suggest the AddressWithMask classes not have any network/container behaviours for a similar reason. If the developer needs these, the .network attribute is only a lookup away.
Another way to approach this would be for the Address object to potentially have a 'network' attribute referencing a Network object. Then there are only two classes, but three use cases are covered: 1) a Network 2) a plain, network-agnostic Address with network == None 3) an Address with an attached Network An Address could be constructed in three ways: Address(ip_number) Address(ip_number, network = <Network instance>) Address(ip_number, mask = <mask>) # constructs and attaches a suitably-masked Network instance We could also have some_network[n] return an Address referring back to the network object it was obtained from. -- Greg
Another way to approach this would be for the Address object to potentially have a 'network' attribute referencing a Network object.
Yes - that's reasonable.
Then there are only two classes, but three use cases are covered:
1) a Network
2) a plain, network-agnostic Address with network == None
3) an Address with an attached Network
An Address could be constructed in three ways:
Address(ip_number)
Address(ip_number, network = <Network instance>)
Address(ip_number, mask = <mask>) # constructs and attaches a suitably-masked Network instance
I think you still need to support the common notations: Address('10.0.0.1') # .network == None Address('10.0.0.1/255.255.255.0') Address('10.0.0.1/24')
We could also have some_network[n] return an Address referring back to the network object it was obtained from.
Yes. (Of course, we're simplifying - there would really be classes for each protocol). -- Andrew McNamara, Senior Developer, Object Craft http://www.object-craft.com.au/
Le Thu, 17 Sep 2009 14:30:28 +1200, Greg Ewing a écrit :
3) an Address with an attached Network
An Address could be constructed in three ways:
Address(ip_number)
Address(ip_number, network = <Network instance>)
Address(ip_number, mask = <mask>) # constructs and attaches a suitably-masked Network instance
We could also have some_network[n] return an Address referring back to the network object it was obtained from.
It seems you are uselessly conflating two perfectly distinct concepts: Address and Network. You also haven't addresses the issue of comparing together (and hashing) two addresses with the same IP but pointing to a different network. No answer to this issue seems satisfactory and obviously right. As it is, -1 from me. Either we only keep two concepts (Address and Network), or if we introduce a third one (AddressWithMask, whatever) for added practicality; but we shouldn't blur the line between the two former canonical concepts under the pretext that a platypus-like Address might be helpful in some particular situations. Regards Antoine.
Antoine Pitrou wrote:
Le Thu, 17 Sep 2009 14:30:28 +1200, Greg Ewing a écrit :
3) an Address with an attached Network
An Address could be constructed in three ways:
Address(ip_number)
Address(ip_number, network = <Network instance>)
Address(ip_number, mask = <mask>) # constructs and attaches a suitably-masked Network instance
We could also have some_network[n] return an Address referring back to the network object it was obtained from.
It seems you are uselessly conflating two perfectly distinct concepts: Address and Network. You also haven't addresses the issue of comparing together (and hashing) two addresses with the same IP but pointing to a different network. No answer to this issue seems satisfactory and obviously right.
As it is, -1 from me. Either we only keep two concepts (Address and Network), or if we introduce a third one (AddressWithMask, whatever) for added practicality; but we shouldn't blur the line between the two former canonical concepts under the pretext that a platypus-like Address might be helpful in some particular situations.
I completely agree with this. By keeping the concepts distinct we can catch mis-uses earlier. If needed, convenience functions (or classes, or whatever) could be layered on top. But the underlying concepts need to be clear. Eric.
Eric Smith wrote:
Antoine Pitrou wrote:
As it is, -1 from me. Either we only keep two concepts (Address and Network), or if we introduce a third one (AddressWithMask, whatever) for added practicality; but we shouldn't blur the line between the two former canonical concepts under the pretext that a platypus-like Address might be helpful in some particular situations.
I completely agree with this. By keeping the concepts distinct we can catch mis-uses earlier. If needed, convenience functions (or classes, or whatever) could be layered on top. But the underlying concepts need to be clear.
That would be my view as well (this includes getting rid of the current duality of IPNetwork by dropping the ip property, only accepting the network address in the normal constructor and having a separate constructor that allows a network object to be created from an arbitrary host address and a netmask) Is-a-2.x-str-a-sequence-of-ASCII-characters-or-a-chunk-of-binary-data?'ly, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia ---------------------------------------------------------------
Nick Coghlan wrote:
Eric Smith wrote:
Antoine Pitrou wrote:
As it is, -1 from me. Either we only keep two concepts (Address and Network), or if we introduce a third one (AddressWithMask, whatever) for added practicality; but we shouldn't blur the line between the two former canonical concepts under the pretext that a platypus-like Address might be helpful in some particular situations. I completely agree with this. By keeping the concepts distinct we can catch mis-uses earlier. If needed, convenience functions (or classes, or whatever) could be layered on top. But the underlying concepts need to be clear.
That would be my view as well (this includes getting rid of the current duality of IPNetwork by dropping the ip property, only accepting the network address in the normal constructor and having a separate constructor that allows a network object to be created from an arbitrary host address and a netmask)
Yes, I think that's the best plan. I could live without AddressWithMask (or whatever name), but it would be a nice convenience.
Is-a-2.x-str-a-sequence-of-ASCII-characters-or-a-chunk-of-binary-data?'ly,
LOL! Perfect. Eric.
On Thu, 17 Sep 2009 at 22:32, Nick Coghlan wrote:
Eric Smith wrote:
Antoine Pitrou wrote:
As it is, -1 from me. Either we only keep two concepts (Address and Network), or if we introduce a third one (AddressWithMask, whatever) for added practicality; but we shouldn't blur the line between the two former canonical concepts under the pretext that a platypus-like Address might be helpful in some particular situations.
I completely agree with this. By keeping the concepts distinct we can catch mis-uses earlier. If needed, convenience functions (or classes, or whatever) could be layered on top. But the underlying concepts need to be clear.
That would be my view as well (this includes getting rid of the current duality of IPNetwork by dropping the ip property, only accepting the network address in the normal constructor and having a separate constructor that allows a network object to be created from an arbitrary host address and a netmask)
I agree as well. If we cannot get consensus on adding a third (or rather fifth and sixth including IPv6) classes for AddressWithMask (and I am no longer an advocate of doing so), then we leave it out and, as suggested by Scott, wait and see what develops and add it later if there is demand for it. --David
On Thu, Sep 17, 2009 at 5:32 AM, Nick Coghlan <ncoghlan@gmail.com> wrote:
Eric Smith wrote:
Antoine Pitrou wrote:
As it is, -1 from me. Either we only keep two concepts (Address and Network), or if we introduce a third one (AddressWithMask, whatever) for added practicality; but we shouldn't blur the line between the two former canonical concepts under the pretext that a platypus-like Address might be helpful in some particular situations.
I completely agree with this. By keeping the concepts distinct we can catch mis-uses earlier. If needed, convenience functions (or classes, or whatever) could be layered on top. But the underlying concepts need to be clear.
That would be my view as well (this includes getting rid of the current duality of IPNetwork by dropping the ip property, only accepting the network address in the normal constructor and having a separate constructor that allows a network object to be created from an arbitrary host address and a netmask)
Again, the same error-catching functionality can be obtained through an option to the constructor. network and broadcast attributes can be renamed to .\1_address to alleviate confusion as well. I mentioned before that IPy's insistence on receiving masked out networks was one of the main reasons I wrote ipaddr to begin with. Having ipaddr mimic this behavior would make it significantly less useful. Removing functionality in the name of avoiding confusion doesn't make sense when the same confusion can be alleviated w/o the loss. off to patch the pep and implement some of the non controversial changes. /peter
Is-a-2.x-str-a-sequence-of-ASCII-characters-or-a-chunk-of-binary-data?'ly, 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
Peter Moody <peter <at> hda3.com> writes:
Again, the same error-catching functionality can be obtained through an option to the constructor. network and broadcast attributes can be renamed to .\1_address to alleviate confusion as well.
My remark was not targetting error-catching of non-zero low bits, it was about the suggestion to have a "network" or "mask" attribute on Address objects. Regards Antoine.
On Thu, Sep 17, 2009 at 9:26 AM, Antoine Pitrou <solipsis@pitrou.net> wrote:
Peter Moody <peter <at> hda3.com> writes:
Again, the same error-catching functionality can be obtained through an option to the constructor. network and broadcast attributes can be renamed to .\1_address to alleviate confusion as well.
My remark was not targetting error-catching of non-zero low bits, it was about the suggestion to have a "network" or "mask" attribute on Address objects.
If I'm reading your reply correctly, then I agree that having a network attribute on an address object doesn't make sense. My remark was targeting Eric's reply of, "By keeping the concepts distinct we can catch mis-uses earlier." Cheers, /peter
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/python-dev%40hda3.com
On Thu, 17 Sep 2009 at 09:16, Peter Moody wrote:
I mentioned before that IPy's insistence on receiving masked out networks was one of the main reasons I wrote ipaddr to begin with. Having ipaddr mimic this behavior would make it significantly less useful. Removing functionality in the name of avoiding confusion doesn't make sense when the same confusion can be alleviated w/o the loss.
We're suggesting moving that functionality (accepting a non-masked IP plus netmask and returning the corresponding Network object) into a different constructor, not eliminating the functionality. --David
On Thu, Sep 17, 2009 at 10:32 AM, R. David Murray <rdmurray@bitdance.com> wrote:
On Thu, 17 Sep 2009 at 09:16, Peter Moody wrote:
I mentioned before that IPy's insistence on receiving masked out networks was one of the main reasons I wrote ipaddr to begin with. Having ipaddr mimic this behavior would make it significantly less useful. Removing functionality in the name of avoiding confusion doesn't make sense when the same confusion can be alleviated w/o the loss.
We're suggesting moving that functionality (accepting a non-masked IP plus netmask and returning the corresponding Network object) into a different constructor, not eliminating the functionality.
Do you mean a new constructor function, ala IPAddress and IPNetwork (so the current classes remain largely the same and the various constructors enforce certain restrictions) or something else? At this point, I'm getting confused with the intermingling of class and constructor names. Cheers, /peter
--David
On Thu, 17 Sep 2009 at 10:38, Peter Moody wrote:
On Thu, Sep 17, 2009 at 10:32 AM, R. David Murray <rdmurray@bitdance.com> wrote:
On Thu, 17 Sep 2009 at 09:16, Peter Moody wrote:
I mentioned before that IPy's insistence on receiving masked out networks was one of the main reasons I wrote ipaddr to begin with. Having ipaddr mimic this behavior would make it significantly less useful. Removing functionality in the name of avoiding confusion doesn't make sense when the same confusion can be alleviated w/o the loss.
We're suggesting moving that functionality (accepting a non-masked IP plus netmask and returning the corresponding Network object) into a different constructor, not eliminating the functionality.
Do you mean a new constructor function, ala IPAddress and IPNetwork (so the current classes remain largely the same and the various constructors enforce certain restrictions) or something else?
At this point, I'm getting confused with the intermingling of class and constructor names.
I mean, eg, IPv4Network.fromHostIP('192.168.1.1/24'). Or some such name. Having another constructor that took an IPv4Address object and a mask would probably be a good idea as well. These could be exposed as appropriately named module level functions instead/as well, of course. I would have IPv4Address itself be strict, and thus the new constructors would compute the network address and call the regular IPv4Address constructor.(*) --David (*) If that's the part you object to (not recording the input IP in the Network object), then clearly you see a need to have an AddressWithMask object of _some_ sort....
R. David Murray wrote:
I would have IPv4Address itself be strict, and thus the new constructors would compute the network address and call the regular IPv4Address constructor.(*)
s/Address/Network/ in this paragraph :) Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia ---------------------------------------------------------------
On Fri, 18 Sep 2009 at 07:45, Nick Coghlan wrote:
R. David Murray wrote:
I would have IPv4Address itself be strict, and thus the new constructors would compute the network address and call the regular IPv4Address constructor.(*)
s/Address/Network/ in this paragraph :)
Ah, yes, sorry for the slip, and thanks for catching it. --David
On Thu, Sep 17, 2009 at 02:04:11PM -0400, R. David Murray wrote:
I mean, eg, IPv4Network.fromHostIP('192.168.1.1/24').
I'd actually suggest to use
net, host = parse_network_and_host("192.168.111.33/24") (IPv4Network('192.168.111.0/24'), IPv4Address('192.168.111.33'))
I think this helps the use case of the short network+gateway notation, while keeping the concepts of network and host address cleanly separate.
I would have IPv4Address itself be strict, and thus the new constructors would compute the network address and call the regular IPv4Address constructor.(*)
Then the regular IPv4Network constructor could be strict and can be used for validation. - Sebastian
On Fri, 18 Sep 2009 at 02:24, Sebastian Rittau wrote:
On Thu, Sep 17, 2009 at 02:04:11PM -0400, R. David Murray wrote:
I mean, eg, IPv4Network.fromHostIP('192.168.1.1/24').
I'd actually suggest to use
net, host = parse_network_and_host("192.168.111.33/24") (IPv4Network('192.168.111.0/24'), IPv4Address('192.168.111.33'))
I think this helps the use case of the short network+gateway notation, while keeping the concepts of network and host address cleanly separate.
Then the regular IPv4Network constructor could be strict and can be used for validation.
I'd be happy with this solution, which was also suggested earlier by someone else (Antoine?). --David
off to patch the pep and implement some of the non controversial changes.
It might be a good idea to add some use-cases to the PEP. -- Andrew McNamara, Senior Developer, Object Craft http://www.object-craft.com.au/
On Thu, Sep 17, 2009 at 6:17 PM, Andrew McNamara <andrewm@object-craft.com.au> wrote:
off to patch the pep and implement some of the non controversial changes.
It might be a good idea to add some use-cases to the PEP.
There are several use-cases in the PEP already. The problem is, for every use-case where one can show that the existing implementation is confusing, I can come up with a use-case showing where the existing implementation makes more sense than anything proposed. Cheers, /peter
-- Andrew McNamara, Senior Developer, Object Craft http://www.object-craft.com.au/
It might be a good idea to add some use-cases to the PEP.
There are several use-cases in the PEP already.
Maybe the use-cases deserve their own section in the PEP, or better yet, be pulled up into the Motivation section.
The problem is, for every use-case where one can show that the existing implementation is confusing, I can come up with a use-case showing where the existing implementation makes more sense than anything proposed.
Uh, I don't think that is the intention of use-cases - they're there to inform the design, rather than to show how a specific implementation can be used. -- Andrew McNamara, Senior Developer, Object Craft http://www.object-craft.com.au/
On Fri, 18 Sep 2009 01:29:21 pm Peter Moody wrote:
On Thu, Sep 17, 2009 at 6:17 PM, Andrew McNamara
<andrewm@object-craft.com.au> wrote:
off to patch the pep and implement some of the non controversial changes.
It might be a good idea to add some use-cases to the PEP.
There are several use-cases in the PEP already.
The problem is, for every use-case where one can show that the existing implementation is confusing, I can come up with a use-case showing where the existing implementation makes more sense than anything proposed.
Please excuse my skepticism, but I find that hard to believe. Given the current API, to test if an address is in the same network as another address, you write: addr_a in addr_b Can you please give a use-case where that makes more sense than the suggested alternative: addr_a in addr_b.network -- Steven D'Aprano
On Thu, 17 Sep 2009 at 20:29, Peter Moody wrote:
On Thu, Sep 17, 2009 at 6:17 PM, Andrew McNamara <andrewm@object-craft.com.au> wrote:
off to patch the pep and implement some of the non controversial changes.
It might be a good idea to add some use-cases to the PEP.
There are several use-cases in the PEP already.
The problem is, for every use-case where one can show that the existing implementation is confusing, I can come up with a use-case showing where the existing implementation makes more sense than anything proposed.
Then all of those use cases should be in the PEP, so we can try to find the best refinement we can of the API for handling all of them. --David
2009/9/18 Peter Moody <peter@hda3.com>:
On Thu, Sep 17, 2009 at 6:17 PM, Andrew McNamara <andrewm@object-craft.com.au> wrote:
off to patch the pep and implement some of the non controversial changes.
It might be a good idea to add some use-cases to the PEP.
There are several use-cases in the PEP already.
The problem is, for every use-case where one can show that the existing implementation is confusing, I can come up with a use-case showing where the existing implementation makes more sense than anything proposed.
Cheers, /peter
For any given use-case there is bound to be an opposing one, but the goal is to satisfy the most common or relevant use-cases that we all experience - can't please all the people all the time etc. I think that alot of the confusion and disagreements surrounding the API are due to the absence of use-cases in the PEP - we can all probably agree an IP address module has intrinsic merit, but how we expect to use it may vary significantly. As a result the discussion seems to be driven by the example implementation, instead of the by the use-cases that make the module worthwhile being added - I would normally think it would be the other way round. Without a clear set of expectations and use-cases, it would also be hard to propose an alternate implementation.
Again, the same error-catching functionality can be obtained through an option to the constructor. network and broadcast attributes can be renamed to .\1_address to alleviate confusion as well.
I mentioned before that IPy's insistence on receiving masked out networks was one of the main reasons I wrote ipaddr to begin with. Having ipaddr mimic this behavior would make it significantly less useful. Removing functionality in the name of avoiding confusion doesn't make sense when the same confusion can be alleviated w/o the loss.
The issue is bigger than error checking - I'm maintaining that a distinction between an Address (singleton, item) and a Network (Container) is useful and should be embraced. The current implementation has already partially gone this route, but hasn't completed the transition, and this does not give the structure to users that it could - there's an obligation on modules in the standard library to provide leadership and clarity without being dictatorial. They are essentially silent mentors. So, while I am not suggesting we build a bondage and discipline machine, I am suggesting that partitioning the functionality differently will result in a better outcome all round. -- Andrew McNamara, Senior Developer, Object Craft http://www.object-craft.com.au/
On Fri, 18 Sep 2009 11:41:32 am Andrew McNamara wrote:
The issue is bigger than error checking - I'm maintaining that a distinction between an Address (singleton, item) and a Network (Container) is useful and should be embraced. The current implementation has already partially gone this route, but hasn't completed the transition, and this does not give the structure to users that it could - there's an obligation on modules in the standard library to provide leadership and clarity without being dictatorial. They are essentially silent mentors.
So, while I am not suggesting we build a bondage and discipline machine, I am suggesting that partitioning the functionality differently will result in a better outcome all round.
As one of those non-expert users, can I give a big THANK YOU to Andrew for this. -- Steven D'Aprano
On Wed, Sep 16, 2009 at 4:59 PM, Greg Ewing <greg.ewing@canterbury.ac.nz>wrote:
Some people have claimed that the gateway address of a network isn't necessarily the zero address in that network.
I'll go further: I don't think it's even legal for the gateway address to be the zero address of the network (and I used to program the embedded software in routers for a living :) ).
If that's true, then you *can't* calculate the network address from a host address and a netmask -- there isn't enough information.
In a router or operating system kernel, an IPv4 address or netmask is stored in a 32-bit unsigned integer. Host addresses, network addresses, and netmasks satisfy the following properties, where & is the bitwise-AND operation: network address & netmask == network address host address & netmask == network address of that host A gateway is just a host that will forward packets. A gateway address has the same properties as a host address and isn't the same as the zero address. Every host has a routing table that contains a list of (network address, gateway, netmask) tuples. To see the list, just run "/sbin/route -n" on any Linux system (and most other Unixes; root is not typically required) or "route print" on a Windows system. To route a packet, the operating system essentially performs the following algorithm: def find_gateway_for_destination(destination_address): for (network_address, gateway, netmask) in list_of_routing_table_entires: if network_address == destination_address & netmask: return gateway raise DestinationUnreachable Furthermore, an IPNetwork object
needs to be able to represent a network address whose address part contains bits that aren't in the mask.
Network addresses never contain bits that aren't in the mask (due to the rule: "network address & netmask == network address"). -- Daniel Stutzbach, Ph.D. President, Stutzbach Enterprises, LLC <http://stutzbachenterprises.com>
Some people have claimed that the gateway address of a network isn't necessarily the zero address in that network.
It almost never is - conventions vary, but it is often the network address plus one, or the broadcast address minus one.
I'll go further: I don't think it's even legal for the gateway address to be the zero address of the network (and I used to program the embedded software in routers for a living :) ).
I don't think the RFCs forbid the zero address being used, and "enlightened" network stacks allow it (typically routers) to achieve better utilisation of the limited IPv4 address space (for a /24 or larger, wasting one address out of 255 isn't too bad, but it is now typical to use much smaller nets - right down to /30).
If that's true, then you *can't* calculate the network address from a host address and a netmask -- there isn't enough information.
You can always calculate the network address from the IP address plus mask - the network address is simply the bits that are not masked. In the olden days, the mask was spelled out in octets (eg 255.255.255.0). But we've moved to a more compact and logical notation where the number of leading significant bits is specified (eg /24). -- Andrew McNamara, Senior Developer, Object Craft http://www.object-craft.com.au/
On Thu, 17 Sep 2009 10:41:37 am Andrew McNamara wrote:
In the olden days, the mask was spelled out in octets (eg 255.255.255.0). But we've moved to a more compact and logical notation where the number of leading significant bits is specified (eg /24).
I hope you're not suggesting the older notation be unsupported? I would expect to be able to use a mask like 255.255.255.192 without having to count bits myself. -- Steven D'Aprano
On Thu, 17 Sep 2009 10:41:37 am Andrew McNamara wrote:
In the olden days, the mask was spelled out in octets (eg 255.255.255.0). But we've moved to a more compact and logical notation where the number of leading significant bits is specified (eg /24).
I hope you're not suggesting the older notation be unsupported? I would expect to be able to use a mask like 255.255.255.192 without having to count bits myself.
No, of course not - I was just explaining the relationship between the two notations for people who may not have been aware. -- Andrew McNamara, Senior Developer, Object Craft http://www.object-craft.com.au/
I don't think the RFCs forbid the zero address being used
RFC 1122 does: "IP addresses are not permitted to have the value 0 or -1 for any of the <Host-number>, <Network-number>, or <Subnet- number> fields (except in the special cases listed above)." RFC 3021 modifies this requirement, allowing the zero address to be used for an 31-bit prefix. Regards, Martin
2009/9/26 "Martin v. Löwis" <martin@v.loewis.de>
I don't think the RFCs forbid the zero address being used
RFC 1122 does: "IP addresses are not permitted to have the value 0 or -1 for any of the <Host-number>, <Network-number>, or <Subnet- number> fields (except in the special cases listed above)."
The current version of the PEP and reference implementation do not mention or deal with IPv4 classful addressing (A, B, C, D and E). It would be good to know if any of this (admittedly older yet no less important) functionality is going to be supported. If the library is to concentrate solely on classless addressing (i.e. CIDR) please can this be stated in future revisions of the PEP.
RFC 3021 modifies this requirement, allowing the zero address to be used for an 31-bit prefix.
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/drkjam%40gmail.com
On Sat, Sep 26, 2009 at 2:07 PM, DrKJam <drkjam@gmail.com> wrote:
The current version of the PEP and reference implementation do not mention or deal with IPv4 classful addressing (A, B, C, D and E). It would be good to know if any of this (admittedly older yet no less important) functionality is going to be supported. If the library is to concentrate solely on classless addressing (i.e. CIDR) please can this be stated in future revisions of the PEP.
Classful addressing was deprecated more than 15 years ago! Quoting RFC 4632: "With the full deployment of CIDR on the Internet, such scenarios are no longer operationally relevant." -- Daniel Stutzbach, Ph.D. President, Stutzbach Enterprises, LLC <http://stutzbachenterprises.com> "The plumage don't enter into it. It's stone dead."
2009/9/26 Daniel Stutzbach <daniel@stutzbachenterprises.com>
On Sat, Sep 26, 2009 at 2:07 PM, DrKJam <drkjam@gmail.com> wrote:
The current version of the PEP and reference implementation do not mention or deal with IPv4 classful addressing (A, B, C, D and E). It would be good to know if any of this (admittedly older yet no less important) functionality is going to be supported. If the library is to concentrate solely on classless addressing (i.e. CIDR) please can this be stated in future revisions of the PEP.
Classful addressing was deprecated more than 15 years ago!
Quoting RFC 4632: "With the full deployment of CIDR on the Internet, such scenarios are no longer operationally relevant."
Interesting as evidence of classful IPv4 behaviour seems fairly pervasive in current IP stacks and software that supports IPv4 addressing (e.g. PostgreSQL inet and cidr data types). Here's an excerpt from the 'ifconfig' man page (taken from an Ubuntu 9.04 install) :- ^^^^^^^^^^^^^^^^^^^^^^^ ... netmask addr Set the IP network mask for this interface. This value defaults to the usual class A, B or C network mask (as derived from the interface IP address). but it can be set to any value. ... ^^^^^^^^^^^^^^^^^^^^^^^ The point being that you can't always assume /32 implicitly for all use cases. Here is how IP addresses without an explicit prefix or netmask are currently handled :-
import ipaddr ipaddr.IPv4Network('10.0.0.1') IPv4Network('10.0.0.1/32')
It may not be something we want to support (you could always force the end user to specify a prefix or netmask explicitly). This is fair enough, but let's indicate that it's a considered choice. Somewhere in the PEP text is might be a good place for treatment of this topic.
-- Daniel Stutzbach, Ph.D. President, Stutzbach Enterprises, LLC <http://stutzbachenterprises.com> "The plumage don't enter into it. It's stone dead."
On Sat, Sep 26, 2009 at 4:57 PM, DrKJam <drkjam@gmail.com> wrote:
2009/9/26 Daniel Stutzbach <daniel@stutzbachenterprises.com>
On Sat, Sep 26, 2009 at 2:07 PM, DrKJam <drkjam@gmail.com> wrote:
The current version of the PEP and reference implementation do not mention or deal with IPv4 classful addressing (A, B, C, D and E). It would be good to know if any of this (admittedly older yet no less important) functionality is going to be supported. If the library is to concentrate solely on classless addressing (i.e. CIDR) please can this be stated in future revisions of the PEP.
Classful addressing was deprecated more than 15 years ago!
Quoting RFC 4632: "With the full deployment of CIDR on the Internet, such scenarios are no longer operationally relevant."
Interesting as evidence of classful IPv4 behaviour seems fairly pervasive in current IP stacks and software that supports IPv4 addressing (e.g. PostgreSQL inet and cidr data types).
PostgreSQL's inet type stores a host address and optionally a network mask. It's cidr type stores a network address and mask. Neither of them are classful.
Here's an excerpt from the 'ifconfig' man page (taken from an Ubuntu 9.04 install) :- netmask addr
Set the IP network mask for this interface. This value defaults to the usual class A, B or C network mask (as derived from the interface IP address). but it can be set to any value.
Since the network mask can be set to any legal value, that means it's stored as CIDR. It falls back on the classful network mask as a default. Undoubtedly that was useful when ifconfig was updated for CIDR. There were still many classful networks and it needed to retain backward compatibility. After all, ifconfig is around 25 years old, and CIDR is only 16. Today, all IP networks are classless (CIDR), and a system administrator would have to do extra work to figure out if the default value happened to be just right for the network they're setting up.
The point being that you can't always assume /32 implicitly for all use cases.
Certainly, which is why the user can explicitly set the netmask.
Here is how IP addresses without an explicit prefix or netmask are currently handled :-
import ipaddr ipaddr.IPv4Network('10.0.0.1') IPv4Network('10.0.0.1/32')
It may not be something we want to support (you could always force the end user to specify a prefix or netmask explicitly). This is fair enough, but let's indicate that it's a considered choice. Somewhere in the PEP text is might be a good place for treatment of this topic.
+1 on forcing the user to specify a netmask explicitly and documenting it. -- Daniel Stutzbach, Ph.D. President, Stutzbach Enterprises, LLC <http://stutzbachenterprises.com>
On Sat, Sep 26, 2009 at 4:27 PM, Daniel Stutzbach <daniel@stutzbachenterprises.com> wrote:
On Sat, Sep 26, 2009 at 4:57 PM, DrKJam <drkjam@gmail.com> wrote:
2009/9/26 Daniel Stutzbach <daniel@stutzbachenterprises.com>
On Sat, Sep 26, 2009 at 2:07 PM, DrKJam <drkjam@gmail.com> wrote:
The current version of the PEP and reference implementation do not mention or deal with IPv4 classful addressing (A, B, C, D and E). It would be good to know if any of this (admittedly older yet no less important) functionality is going to be supported. If the library is to concentrate solely on classless addressing (i.e. CIDR) please can this be stated in future revisions of the PEP.
I'll call this out in the PEP if necessary. As mentioned elsewhere, classful addressing is so long deprecated that I would expect it to cause confusion if it was assumed.
Classful addressing was deprecated more than 15 years ago!
Quoting RFC 4632: "With the full deployment of CIDR on the Internet, such scenarios are no longer operationally relevant."
Interesting as evidence of classful IPv4 behaviour seems fairly pervasive in current IP stacks and software that supports IPv4 addressing (e.g. PostgreSQL inet and cidr data types).
PostgreSQL's inet type stores a host address and optionally a network mask. It's cidr type stores a network address and mask. Neither of them are classful.
Here's an excerpt from the 'ifconfig' man page (taken from an Ubuntu 9.04 install) :- netmask addr
Set the IP network mask for this interface. This value defaults to the usual class A, B or C network mask (as derived from the interface IP address). but it can be set to any value.
Since the network mask can be set to any legal value, that means it's stored as CIDR. It falls back on the classful network mask as a default. Undoubtedly that was useful when ifconfig was updated for CIDR. There were still many classful networks and it needed to retain backward compatibility. After all, ifconfig is around 25 years old, and CIDR is only 16.
Today, all IP networks are classless (CIDR), and a system administrator would have to do extra work to figure out if the default value happened to be just right for the network they're setting up.
The point being that you can't always assume /32 implicitly for all use cases.
Certainly, which is why the user can explicitly set the netmask.
Here is how IP addresses without an explicit prefix or netmask are currently handled :-
import ipaddr ipaddr.IPv4Network('10.0.0.1') IPv4Network('10.0.0.1/32')
It may not be something we want to support (you could always force the end user to specify a prefix or netmask explicitly). This is fair enough, but let's indicate that it's a considered choice. Somewhere in the PEP text is might be a good place for treatment of this topic.
+1 on forcing the user to specify a netmask explicitly and documenting it.
-(1/0) forcing a user to include a prefixlen when creating a network object doesn't actually serve any useful purpose. when dealing with network objects, it's very useful (and common) to assume a /32 prefix length when none is supplied. Cheers, /peter
-- Daniel Stutzbach, Ph.D. President, Stutzbach Enterprises, LLC
_______________________________________________ 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 16 Sep 2009, at 01:05, Peter Moody wrote:
On Tue, Sep 15, 2009 at 4:34 PM, Scott Dial <scott+python-dev@scottdial.com> wrote:
R. David Murray wrote:
On Tue, 15 Sep 2009 at 21:58, Antoine Pitrou wrote:
Le mardi 15 septembre 2009 à 15:48 -0400, R. David Murray a écrit :
However, I do not think that the proposed API should accept, eg, IPv4Network ('192.168.1.1/24') as valid. That's just too confusing and error prone.
Indeed, it should throw some kind of ValueError instead.
Peter, what do you think?
I disagree. It seems overly pedantic to throw a valueerror on this. IPy does (used to do?) this and it's one of the primary reasons I wrote ipaddr.
I've seen user interfaces accept 192.168.1.1/24 as a short cut to set the ipaddr and netmask on an interface. For that use being able to parse that string into an IP Address and a Net Mask is what they want. If this is a common idiom having a utility function that returned an IPv4Address('192.168.1.1') and IPv4Network('192.168.0.0') would be useful. If someone really thinks that '192.168.1.1/16' is a network any good UI should detect it is invalid report that to the user. If you think this is a decision that the only the caller can decide why not add a keyword param to control the parsing? IPv4Network( '192.168.1.1/16', syntax='loose' ) (I'm sure syntax='loose' is not right but you get the idea.) Barry
On Sat, 26 Sep 2009 11:23:14 pm Barry Scott wrote:
I've seen user interfaces accept 192.168.1.1/24 as a short cut to set the ipaddr and netmask on an interface.
For that use being able to parse that string into an IP Address and a Net Mask is what they want.
I think you're at least the second person who has requested this functionality, or something similar.
If this is a common idiom having a utility function that returned an IPv4Address('192.168.1.1') and IPv4Network('192.168.0.0') would be useful.
If someone really thinks that '192.168.1.1/16' is a network any good UI should detect it is invalid report that to the user.
Currently the ipaddr module accepts that without complaint:
ipaddr.IPv4Network('192.168.1.1/16') IPv4Network('192.168.1.1/16')
The current behaviour is confusing to me. For example:
netw1 = ipaddr.IPv4Network('192.168.1.1/24') netw2 = ipaddr.IPv4Network('192.168.1.0/24') netw1 == netw2 False list(netw1) == list(netw2) True
Two networks, containing exactly the same range of addresses, but they don't compare equal. I'm not convinced that netw1 should even be allowed, but if it is, surely it should be turned into canonical form netw2? E.g. I would expect this:
ipaddr.IPv4Network('192.168.1.1/24') IPv4Network('192.168.1.0/24')
but that's not what it does. -- Steven D'Aprano
I again invite interested parties to continue this discussion on ipaddr-py-dev@googlegroups.com. we're pushing 250 messages on PEP 3144 at this point; well beyond what most folks would call a "long open-ended discussion". anyway:
The current behaviour is confusing to me. For example:
netw1 = ipaddr.IPv4Network('192.168.1.1/24') netw2 = ipaddr.IPv4Network('192.168.1.0/24') netw1 == netw2 False list(netw1) == list(netw2) True
I think you're intentionally confusing yourself here. 192.168.1.1 clearly doesn't equal 192.168.1.0, so I don't know why you'd expect 192.168.1.1/24 to equal 192.168.1.0/24.
Two networks, containing exactly the same range of addresses, but they don't compare equal. I'm not convinced that netw1 should even be allowed, but if it is, surely it should be turned into canonical form netw2? E.g. I would expect this:
ipaddr.IPv4Network('192.168.1.1/24') IPv4Network('192.168.1.0/24')
but that's not what it does.
now you're confusing me as before you've asked for this to either: 1. Raise an exception 2. Return two objects. your unconfusing (to you) example does neither one of those.
-- Steven D'Aprano _______________________________________________ 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:
I again invite interested parties to continue this discussion on ipaddr-py-dev@googlegroups.com. we're pushing 250 messages on PEP 3144 at this point; well beyond what most folks would call a "long open-ended discussion".
anyway:
The current behaviour is confusing to me. For example:
netw1 = ipaddr.IPv4Network('192.168.1.1/24') netw2 = ipaddr.IPv4Network('192.168.1.0/24') netw1 == netw2 False list(netw1) == list(netw2) True
I think you're intentionally confusing yourself here. 192.168.1.1 clearly doesn't equal 192.168.1.0, so I don't know why you'd expect 192.168.1.1/24 to equal 192.168.1.0/24.
No, this is exactly the "dual purpose" nature of IPNetwork that people have been complaining about: 192.168.1.1 & 255.255.255.0 == 192.168.1.0 & 255.255.255.0, so the two objects describe the exact same network, but the network objects don't currently respect their own netmask, instead remembering which particular host happened to be used to derive the network ID. "Arbitrary network host with associated netmask" and "IP Network" are different concepts, but the library currently uses a single class interface (IPNetwork) for both of them. What we're asking for is for the "ip" attribute to be removed from IP Network, with the constructor either forgetting the host IP that was used to derive the network address, or else only accepting the correct network address in the constructor and providing a separate helper function or class method to create an IPNetwork object from an arbitrary hostname. Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia ---------------------------------------------------------------
On Sat, Sep 26, 2009 at 10:38 PM, Nick Coghlan <ncoghlan@gmail.com> wrote:
Peter Moody wrote:
I again invite interested parties to continue this discussion on ipaddr-py-dev@googlegroups.com. we're pushing 250 messages on PEP 3144 at this point; well beyond what most folks would call a "long open-ended discussion".
anyway:
The current behaviour is confusing to me. For example:
netw1 = ipaddr.IPv4Network('192.168.1.1/24') netw2 = ipaddr.IPv4Network('192.168.1.0/24') netw1 == netw2 False list(netw1) == list(netw2) True
I think you're intentionally confusing yourself here. 192.168.1.1 clearly doesn't equal 192.168.1.0, so I don't know why you'd expect 192.168.1.1/24 to equal 192.168.1.0/24.
No, this is exactly the "dual purpose" nature of IPNetwork that people have been complaining about: 192.168.1.1 & 255.255.255.0 == 192.168.1.0 & 255.255.255.0, so the two objects describe the exact same network, but the network objects don't currently respect their own netmask, instead remembering which particular host happened to be used to derive the network ID.
"Arbitrary network host with associated netmask" and "IP Network" are different concepts, but the library currently uses a single class interface (IPNetwork) for both of them.
What we're asking for is for the "ip" attribute to be removed from IP Network, with the constructor either forgetting the host IP that was used to derive the network address, or else only accepting the correct network address in the constructor and providing a separate helper function or class method to create an IPNetwork object from an arbitrary hostname.
what you want is strict=True, just checked in. I've been meaning to send an update to the PEP explaining why this choice was made. I'm hoping this will ameliorate your confusion. Cheers, /peter
Cheers, Nick.
-- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia ---------------------------------------------------------------
Peter Moody wrote:
what you want is strict=True, just checked in. I've been meaning to send an update to the PEP explaining why this choice was made. I'm hoping this will ameliorate your confusion.
If the ip property remains and equality is still broken as Steven describes, then no, it won't really alleviate my concerns. I've also previously registered my objections to using a boolean flag for this instead of a separate method. However, I'll wait and see what the PEP update says before commenting further. Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia ---------------------------------------------------------------
On Sat, Sep 26, 2009 at 11:08 PM, Nick Coghlan <ncoghlan@gmail.com> wrote:
Peter Moody wrote:
what you want is strict=True, just checked in. I've been meaning to send an update to the PEP explaining why this choice was made. I'm hoping this will ameliorate your confusion.
If the ip property remains and equality is still broken as Steven describes, then no, it won't really alleviate my concerns.
I've also previously registered my objections to using a boolean flag for this instead of a separate method.
However, I'll wait and see what the PEP update says before commenting further.
I've mailed the PEP patch in, hopefully it will be checked in and updated shortly. To be explicit though, unless I'm drastically misreading what you're asking for, I consider the design you're proposing to be broken from a usability perspective (striving for academic/pedantic correctness over accepted practice). I have no intention of adding any sort of AddressWithNetmask classes or making other fundamental design changes you've suggested. If what the community requires is the library you've described, then ipaddr is not that library. Cheers, /peter
Cheers, Nick.
-- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia ---------------------------------------------------------------
Peter Moody <peter <at> hda3.com> writes:
To be explicit though, unless I'm drastically misreading what you're asking for, I consider the design you're proposing to be broken from a usability perspective (striving for academic/pedantic correctness over accepted practice).
It is certainly not academic correctness, it is concern over the understandibility of the library. The behaviour you are proposing is confusing, and even if you think it is more practical (which I doubt it is), it should still be avoided IMO. While "192.168.1.2/24" may be an accepted notation in some situations, it is not a notation for a *network* but for an (address, mask) pair, or an (address, network) pair. There was a proposal to have a separate parse_address_and_mask method which would return a (Address, Network) tuple, I still don't know why you don't seem to consider it seriously, rather than trying to make the Network class a kind of all-in-one type conflating different concepts. Regards Antoine.
Antoine Pitrou writes:
There was a proposal to have a separate parse_address_and_mask method which would return a (Address, Network) tuple, I still don't know why you don't seem to consider it seriously, rather than trying to make the Network class a kind of all-in-one type conflating different concepts.
Because he thinks about the problem space differently from you. Specifically, AFAICS he does not (maybe even "can't") see a reason to distinguish an AddressWithMask from a Network. If so, it's a reasonable API choice for him to choose not to have separate classes to represent such similar concepts. That's all there is to it. I personally do not have a problem with that, except that you apparently can't grasp his way of thinking, and he apparently can't grasp yours. I'm -1 on PEP 3144 primarily because of this communications gap. Secondarily because I agree that it's unnatural that a Network instance can have an arbitrary distinguished address other than those defined in the RFCs (the network and broadcast addresses), especially since it matters to equality comparisons. (But I personally would use ipaddr if it were in the stdlib despite that.)
I personally do not have a problem with that, except that you apparently can't grasp his way of thinking, and he apparently can't grasp yours.
If I was the only one disagreeing it wouldn't be that annoying (except for me :-)).
I'm -1 on PEP 3144 primarily because of this communications gap.
I must say I have started to lean in that direction, too. If it is not possible to produce a result (a PEP) that solves all major design issues, it will produce the kind of little-liked modules that people have recently complained about in an stdlib-sig thread. Regards Antoine.
On Sun, Sep 27, 2009 at 4:23 AM, Antoine Pitrou <solipsis@pitrou.net> wrote:
Peter Moody <peter <at> hda3.com> writes:
To be explicit though, unless I'm drastically misreading what you're asking for, I consider the design you're proposing to be broken from a usability perspective (striving for academic/pedantic correctness over accepted practice).
It is certainly not academic correctness, it is concern over the understandibility of the library. The behaviour you are proposing is confusing, and even if you think it is more practical (which I doubt it is), it should still be avoided IMO. While "192.168.1.2/24" may be an accepted notation in some situations, it is not a notation for a *network* but for an (address, mask) pair, or an (address, network) pair.
There was a proposal to have a separate parse_address_and_mask method which would return a (Address, Network) tuple, I still don't know why you don't seem to consider it seriously, rather than trying to make the Network class a kind of all-in-one type conflating different concepts.
The reason (aside from the name) that I'm not going to include this in ipaddr is that it would require the user to deal with two objects when one would suffice. It's similar to getting two return values from float(). integer, fraction = float('1.25') crazy, right? Finally, to Stephen's point about seeing the other side of the argument, I wrote this offlist a week ago: I *understand* what you're saying, I *understand* that 192.168.1.1/24 isn't a network, 192.168.1.0/24 is a network, and 192.168.1.1 is an ip address on that network and it has an associated netmask that helps describe its network, etc. etc. what I'm saying is that, enforcing that restriction by introducing 2 new classes (ipv4 is not comparable with ipv6, I've actually got a good quote from Vint Cerf about this, so any AddressWithNetmask (?!?) class would have to be duplicated for both addr types) or something else as of yet described, is not useful. it is in fact, detrimental (optionally enforcing that restriction via an argument to the Network constructors is, however, useful) Cheers, /peter
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/python-dev%40hda3.com
Peter Moody <peter <at> hda3.com> writes:
The reason (aside from the name) that I'm not going to include this in ipaddr is that it would require the user to deal with two objects when one would suffice.
You make it sound like it's a burden, but "dealing" with two objects is not something extraordinary or bizarre, it happens all the time when you do network programming: e.g. ('127.0.0.1', 80). (or would you argue that Address objects should have an optional distinguishing port number, for "convenience" reasons?) If you need the two objects, whether you access them through separate variables (`network` and `host`) or through attribute access (`network` and `network.host`) doesn't really matter. You can even pretend the tuple is an atomic object and store it as-is if you want. I'm not sure what annoys you here.
It's similar to getting two return values from float().
I don't see how it's similar, since a float is a clearly defined atomic entity. Most float operations become meaningless if you consider the integral and the fractional part separately. Regards Antoine.
On Sun, Sep 27, 2009 at 10:22 AM, Antoine Pitrou <solipsis@pitrou.net> wrote:
Peter Moody <peter <at> hda3.com> writes:
The reason (aside from the name) that I'm not going to include this in ipaddr is that it would require the user to deal with two objects when one would suffice.
You make it sound like it's a burden, but "dealing" with two objects is not something extraordinary or bizarre, it happens all the time when you do network programming: e.g. ('127.0.0.1', 80).
(or would you argue that Address objects should have an optional distinguishing port number, for "convenience" reasons?)
I'm not sure what you're talking about, I've never argued to add layer 4 information to ipaddr.
If you need the two objects, whether you access them through separate variables (`network` and `host`) or through attribute access (`network` and `network.host`) doesn't really matter. You can even pretend the tuple is an atomic object and store it as-is if you want. I'm not sure what annoys you here.
this is tautological. if you need two objects, then two objects is what you need. I'm saying that you don't need two objects for this, that common accepted practice is to represent this as one. Note, there is *nothing* stopping you currently from using two objects for this, an IPAddress object and a strict=True IPNetwork object. I'm not sure what annoys you about this.
It's similar to getting two return values from float().
I don't see how it's similar, since a float is a clearly defined atomic entity. Most float operations become meaningless if you consider the integral and the fractional part separately.
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/python-dev%40hda3.com
Peter Moody <peter <at> hda3.com> writes:
(or would you argue that Address objects should have an optional
distinguishing
port number, for "convenience" reasons?)
I'm not sure what you're talking about, I've never argued to add layer 4 information to ipaddr.
It was an analogy, just like your "float" analogy.
I'm not sure what annoys you about this.
I have already explained it: what annoys me is that it makes `Network` a hybrid object conflating two independent concepts, and makes the library less understandable as a result. Others have already pointed out that it makes operations like equality confusing. Regards Antoine.
On Sun, Sep 27, 2009 at 11:17 AM, Antoine Pitrou <solipsis@pitrou.net> wrote:
Peter Moody <peter <at> hda3.com> writes:
(or would you argue that Address objects should have an optional
distinguishing
port number, for "convenience" reasons?)
I'm not sure what you're talking about, I've never argued to add layer 4 information to ipaddr.
It was an analogy, just like your "float" analogy.
I'm not sure what annoys you about this.
I have already explained it: what annoys me is that it makes `Network` a hybrid object conflating two independent concepts, and makes the library less understandable as a result.
I understand that this is your assertion. Here's the thing, your use case is already supported. IPv?Network objects can only be created of network addresses, exceptions are raised if all the host bits aren't 0, you can create and only deal with IPv4Address('192.168.1.1') and IPv4Network('192.168.1.0/24', strict=True) etc etc. That's not how I (nor many other network administrators) would use it, but it's doable. what you're claiming is that my use case is invalid. that's what I claim is broken. There have been folks on both sides claiming that this design is both fundamentally confusing and fundamentally sound. The confused have obviously been more vocal and less willing to compromise. So, the basic design of the library stands as it is, minor implementation and documentation bugs not withstanding. I'm not going to make ipaddr less useful (strictly removing functionality), more bulky and confusing (adding more confusingly named classes and methods) or otherwise break the library in a vain attempt to have it included in the stdlib. Cheers, /peter
Others have already pointed out that it makes operations like equality confusing.
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/python-dev%40hda3.com
On Sep 27, 2009, at 3:18 PM, Peter Moody wrote:
administrators) would use it, but it's doable. what you're claiming is that my use case is invalid.
that's what I claim is broken.
He's claiming your solution to address your use case is confusing, not that the use case is invalid.
I'm not going to make ipaddr less useful (strictly removing functionality), more bulky and confusing (adding more confusingly named classes and methods) or otherwise break the library in a vain attempt to have it included in the stdlib.
If I understand correctly, the proposal for addressing the issue is to make two rather simple changes: 1) if strict=False, mask off the bits described by the netmask when creating an IPNetwork, such that the host bits are always 0. 2) add a single new function: def parse_net_and_addr(s): return (IPNetwork(s), IPAddress(s.split('/')[0])) James
On Sun, Sep 27, 2009 at 12:40 PM, James Y Knight <foom@fuhm.net> wrote:
On Sep 27, 2009, at 3:18 PM, Peter Moody wrote:
administrators) would use it, but it's doable. what you're claiming is that my use case is invalid.
that's what I claim is broken.
He's claiming your solution to address your use case is confusing, not that the use case is invalid.
this isn't actually true. Steven D'Aprano wrote: Could you explain what benefit there is for allowing the user to create network objects that don't represent networks? Is there a use-case where these networks-that-aren't-networks are something other than a typo? Under what circumstances would I want to specify a network as 192.168.1.1/24 instead of 192.168.1.0/24? that pretty flatly states that my use case is invalid.
I'm not going to make ipaddr less useful (strictly removing functionality), more bulky and confusing (adding more confusingly named classes and methods) or otherwise break the library in a vain attempt to have it included in the stdlib.
If I understand correctly, the proposal for addressing the issue is to make two rather simple changes:
i wish it were this easy.
1) if strict=False, mask off the bits described by the netmask when creating an IPNetwork, such that the host bits are always 0.
I haven't heard anyone suggest auto-masking bits, but otherwise that would be strict=True.
2) add a single new function:
def parse_net_and_addr(s): return (IPNetwork(s), IPAddress(s.split('/')[0]))
I've only heard talk of new classes and new methods, not new constructor functions. In fact, when I asked for explicit clarification of what was required, a new constructor function "ala IPAddress and IPNetwork (so the current classes remain largely the same and the various constructors enforce certain restrictions)", I was told, no, a new object AddressWithMask was actually required. I've no problem with a constructor like this, but this is not what people have been asking for. Cheers, /peter
James
Peter Moody <peter <at> hda3.com> writes:
On Sun, Sep 27, 2009 at 12:40 PM, James Y Knight <foom <at> fuhm.net> wrote:
On Sep 27, 2009, at 3:18 PM, Peter Moody wrote:
administrators) would use it, but it's doable. what you're claiming is that my use case is invalid.
that's what I claim is broken.
He's claiming your solution to address your use case is confusing, not that the use case is invalid.
this isn't actually true.
Steven D'Aprano wrote:
[...] That's Steven, your original sentence was about me.
1) if strict=False, mask off the bits described by the netmask when creating an IPNetwork, such that the host bits are always 0.
I haven't heard anyone suggest auto-masking bits, but otherwise that would be strict=True.
I would expect strict=True to raise an error if the lower bits are non-zero, not to silently erase them. strict=False would be the option that silently erases lower bits. (that's why it's named `strict`, after all :-))
2) add a single new function:
def parse_net_and_addr(s): return (IPNetwork(s), IPAddress(s.split('/')[0]))
I've only heard talk of new classes and new methods, not new constructor functions.
Well, "method" in that context meant "class method" since the results aren't dependent on a particular instance. Of course, both a class method or a module-level function would be fine. Regards Antoine.
On Sun, Sep 27, 2009 at 1:15 PM, Antoine Pitrou <solipsis@pitrou.net> wrote:
Peter Moody <peter <at> hda3.com> writes:
On Sun, Sep 27, 2009 at 12:40 PM, James Y Knight <foom <at> fuhm.net> wrote:
On Sep 27, 2009, at 3:18 PM, Peter Moody wrote:
administrators) would use it, but it's doable. what you're claiming is that my use case is invalid.
that's what I claim is broken.
He's claiming your solution to address your use case is confusing, not that the use case is invalid.
this isn't actually true.
Steven D'Aprano wrote:
[...]
That's Steven, your original sentence was about me.
my original sentence was about everyone who was arguing that the current implementation was designed for an invalid use-case. it was in reply to your email, but it was to everyone (you, Nick, rdm, Steven, etc)
1) if strict=False, mask off the bits described by the netmask when creating an IPNetwork, such that the host bits are always 0.
I haven't heard anyone suggest auto-masking bits, but otherwise that would be strict=True.
I would expect strict=True to raise an error if the lower bits are non-zero, not to silently erase them. strict=False would be the option that silently erases lower bits. (that's why it's named `strict`, after all :-))
2) add a single new function:
def parse_net_and_addr(s): return (IPNetwork(s), IPAddress(s.split('/')[0]))
I've only heard talk of new classes and new methods, not new constructor functions.
Well, "method" in that context meant "class method" since the results aren't dependent on a particular instance. Of course, both a class method or a module-level function would be fine.
so this is not the response I got when I asked what was required before. Would adding this constructor function satisfy your concerns (given sensible strict settings in the constructor, etc)?
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/python-dev%40hda3.com
Peter Moody <peter <at> hda3.com> writes:
def parse_net_and_addr(s): return (IPNetwork(s), IPAddress(s.split('/')[0]))
I've only heard talk of new classes and new methods, not new constructor functions.
Well, "method" in that context meant "class method" since the results aren't dependent on a particular instance. Of course, both a class method or a module-level function would be fine.
so this is not the response I got when I asked what was required before. Would adding this constructor function satisfy your concerns (given sensible strict settings in the constructor, etc)?
Assuming the Network type loses the notion of a specific host (or host address, or `ip`) attached to it, yes. Or to put it more clearly:
Network('192.168.0.1/24', strict=False) Network('192.168.0.0/24') Network('192.168.0.1/24', strict=False) == Network('192.168.0.0/24') True
Regards Antoine.
On Sun, Sep 27, 2009 at 1:49 PM, Antoine Pitrou <solipsis@pitrou.net> wrote:
Peter Moody <peter <at> hda3.com> writes:
def parse_net_and_addr(s): return (IPNetwork(s), IPAddress(s.split('/')[0]))
I've only heard talk of new classes and new methods, not new constructor functions.
Well, "method" in that context meant "class method" since the results aren't dependent on a particular instance. Of course, both a class method or a module-level function would be fine.
so this is not the response I got when I asked what was required before. Would adding this constructor function satisfy your concerns (given sensible strict settings in the constructor, etc)?
Assuming the Network type loses the notion of a specific host (or host address, or `ip`) attached to it, yes.
this is "less useful (strictly removing functionality)" and is an example of what I explicitly said I was not going to do with ipaddr. Cheers, /peter
Or to put it more clearly:
Network('192.168.0.1/24', strict=False) Network('192.168.0.0/24') Network('192.168.0.1/24', strict=False) == Network('192.168.0.0/24') True
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/python-dev%40hda3.com
Peter Moody <peter <at> hda3.com> writes:
this is "less useful (strictly removing functionality)" and is an example of what I explicitly said I was not going to do with ipaddr.
(please note the conditional wording here) Assuming that a significant number of people agree that there is a design problem, if you don't want to make the necessary changes, then I don't see a reason why ipaddr would enter the stdlib. The functionality (IP address handling) hasn't really seen a huge demand. On stdlib-sig recently, a number of people complained that our criteria for including existing libraries in the stdlib should be higher (they complained about the quality of some existing modules, including optparse, which by the way prompted the current proposal to get argparse in the stdlib). I think this PEP is a good moment to judge and decide how demanding or tolerant we (and especially the complainers ;-)) want to be. Regards Antoine.
On Sun, Sep 27, 2009 at 3:32 PM, Antoine Pitrou <solipsis@pitrou.net> wrote:
Peter Moody <peter <at> hda3.com> writes:
this is "less useful (strictly removing functionality)" and is an example of what I explicitly said I was not going to do with ipaddr.
(please note the conditional wording here) Assuming that a significant number of people agree that there is a design problem, if you don't want to make the necessary changes, then I don't see a reason why ipaddr would enter the stdlib.
I've never said otherwise. In fact, from an email last night, "If what the community requires is the library you've described, then ipaddr is not that library." The changes *you* require make ipaddr significantly less useful to me. I'm not prepared to make those changes in an attempt seek acceptance to the stdlib, especially if the stdlib is in such flux that I'll get to do this again in 18 months.
The functionality (IP address handling) hasn't really seen a huge demand.
then no one would be the worse off if I don't make those suggested changes.
On stdlib-sig recently, a number of people complained that our criteria for including existing libraries in the stdlib should be higher (they complained about the quality of some existing modules, including optparse, which by the way prompted the current proposal to get argparse in the stdlib). I think this PEP is a good moment to judge and decide how demanding or tolerant we (and especially the complainers ;-)) want to be.
Sounds like design by committee to satisfy the squeakiest wheel. I'm trying, but I can't think of anything worse. Cheers, /peter
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/python-dev%40hda3.com
Peter Moody <peter <at> hda3.com> writes:
I've never said otherwise. In fact, from an email last night, "If what the community requires is the library you've described, then ipaddr is not that library." The changes *you* require make ipaddr significantly less useful to me. I'm not prepared to make those changes in an attempt seek acceptance to the stdlib, especially if the stdlib is in such flux that I'll get to do this again in 18 months.
Well, then I'm not sure why we have a PEP at all. If you don't want any significant changes and if you consider it to be *your* library, ipaddr can remain a third-party package that interested people can easily install (no pun ;-)) since AFAIK it's pure Python. It will also make maintenance easier for you, while freeing us (core developers) from having to bother about it in our daily development tasks. At least that's what I would advocate right now - not sure about what others think. Regards Antoine.
On Sun, Sep 27, 2009 at 5:32 PM, Antoine Pitrou <solipsis@pitrou.net> wrote:
Peter Moody <peter <at> hda3.com> writes:
I've never said otherwise. In fact, from an email last night, "If what the community requires is the library you've described, then ipaddr is not that library." The changes *you* require make ipaddr significantly less useful to me. I'm not prepared to make those changes in an attempt seek acceptance to the stdlib, especially if the stdlib is in such flux that I'll get to do this again in 18 months.
Well, then I'm not sure why we have a PEP at all. If you don't want any significant changes and if you consider it to be *your* library, ipaddr can remain a third-party package that interested people can easily install (no pun ;-)) since AFAIK it's pure Python. It will also make maintenance easier for you, while freeing us (core developers) from having to bother about it in our daily development tasks.
At least that's what I would advocate right now - not sure about what others think.
I think Peter is pretty frustrated by the many attacks on "his" library. There are probably a number of different things going on simultaneous: Peter has been driven into the defense by attacks both reasonable and unreasonable, there have been misunderstandings all around, teasing out use cases (by both parties) has been a problem. Things might have gone differently if the PEP had started out with multiple authors. Maybe it's not too late to add one or more other interested parties to the PEP with the purpose of making the PEP more clearly the result of a consensus-gathering process. Any volunteers? At the same time I don't think a complete reset of the proposed API is necessary. I am rather more thinking of judicious API tweaks in order to cover some new use cases, without requiring a complete rewrite or destroying the usability of the proposal for Peter's original use cases. (In general I am pretty happy with the ipaddr code and API; it looks like what I would have done, but then I am blissfully unaware of some of the issues brought up in this thread.) -- --Guido van Rossum (home page: http://www.python.org/~guido/)
[cc += david moss] On Mon, Sep 28, 2009 at 9:39 AM, Guido van Rossum <guido@python.org> wrote:
On Sun, Sep 27, 2009 at 5:32 PM, Antoine Pitrou <solipsis@pitrou.net> wrote:
Peter Moody <peter <at> hda3.com> writes:
I've never said otherwise. In fact, from an email last night, "If what the community requires is the library you've described, then ipaddr is not that library." The changes *you* require make ipaddr significantly less useful to me. I'm not prepared to make those changes in an attempt seek acceptance to the stdlib, especially if the stdlib is in such flux that I'll get to do this again in 18 months.
Well, then I'm not sure why we have a PEP at all. If you don't want any significant changes and if you consider it to be *your* library, ipaddr can remain a third-party package that interested people can easily install (no pun ;-)) since AFAIK it's pure Python. It will also make maintenance easier for you, while freeing us (core developers) from having to bother about it in our daily development tasks.
At least that's what I would advocate right now - not sure about what others think.
I think Peter is pretty frustrated by the many attacks on "his" library. There are probably a number of different things going on simultaneous: Peter has been driven into the defense by attacks both reasonable and unreasonable, there have been misunderstandings all around, teasing out use cases (by both parties) has been a problem.
Things might have gone differently if the PEP had started out with multiple authors. Maybe it's not too late to add one or more other interested parties to the PEP with the purpose of making the PEP more clearly the result of a consensus-gathering process. Any volunteers?
David called me a little over a week ago and expressed an interest in doing exactly this cross continent/ocean coordination has been a little difficult thus far and I'm not certain what his feelings on this are now.
At the same time I don't think a complete reset of the proposed API is necessary. I am rather more thinking of judicious API tweaks in order to cover some new use cases, without requiring a complete rewrite or destroying the usability of the proposal for Peter's original use cases. (In general I am pretty happy with the ipaddr code and API; it looks like what I would have done, but then I am blissfully unaware of some of the issues brought up in this thread.)
-- --Guido van Rossum (home page: http://www.python.org/~guido/) _______________________________________________ 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
2009/9/28 Peter Moody <peter@hda3.com>
[cc += david moss]
On Mon, Sep 28, 2009 at 9:39 AM, Guido van Rossum <guido@python.org> wrote:
On Sun, Sep 27, 2009 at 5:32 PM, Antoine Pitrou <solipsis@pitrou.net> wrote:
Peter Moody <peter <at> hda3.com> writes:
I've never said otherwise. In fact, from an email last night, "If what the community requires is the library you've described, then ipaddr is not that library." The changes *you* require make ipaddr significantly less useful to me. I'm not prepared to make those changes in an attempt seek acceptance to the stdlib, especially if the stdlib is in such flux that I'll get to do this again in 18 months.
Well, then I'm not sure why we have a PEP at all. If you don't want any significant changes and if you consider it to be *your* library, ipaddr can remain a third-party package that interested people can easily install (no pun ;-)) since AFAIK it's pure Python. It will also make maintenance easier for you, while freeing us (core developers) from having to bother about it in our daily development tasks.
At least that's what I would advocate right now - not sure about what others think.
I think Peter is pretty frustrated by the many attacks on "his" library. There are probably a number of different things going on simultaneous: Peter has been driven into the defense by attacks both reasonable and unreasonable, there have been misunderstandings all around, teasing out use cases (by both parties) has been a problem.
Things might have gone differently if the PEP had started out with multiple authors. Maybe it's not too late to add one or more other interested parties to the PEP with the purpose of making the PEP more clearly the result of a consensus-gathering process. Any volunteers?
David called me a little over a week ago and expressed an interest in doing exactly this cross continent/ocean coordination has been a little difficult thus far and I'm not certain what his feelings on this are now.
Sure, I'm happy to volunteer and help out. Let's have a good hard look at all this and see what we can come up with.
At the same time I don't think a complete reset of the proposed API is necessary. I am rather more thinking of judicious API tweaks in order to cover some new use cases, without requiring a complete rewrite or destroying the usability of the proposal for Peter's original use cases. (In general I am pretty happy with the ipaddr code and API; it looks like what I would have done, but then I am blissfully unaware of some of the issues brought up in this thread.)
-- --Guido van Rossum (home page: http://www.python.org/~guido/<http://www.python.org/%7Eguido/> ) _______________________________________________ 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
Guido van Rossum <guido <at> python.org> writes:
At the same time I don't think a complete reset of the proposed API is necessary. I am rather more thinking of judicious API tweaks in order to cover some new use cases, without requiring a complete rewrite or destroying the usability of the proposal for Peter's original use cases.
I think the current API is mostly fine as well, except for one roadblock for which several people has raised concerns, and that Peter stated he doesn't want to change. Regards Antoine.
On Mon, Sep 28, 2009 at 11:17 AM, Antoine Pitrou <solipsis@pitrou.net> wrote:
Guido van Rossum <guido <at> python.org> writes:
At the same time I don't think a complete reset of the proposed API is necessary. I am rather more thinking of judicious API tweaks in order to cover some new use cases, without requiring a complete rewrite or destroying the usability of the proposal for Peter's original use cases.
I think the current API is mostly fine as well, except for one roadblock for which several people has raised concerns, and that Peter stated he doesn't want to change.
Well, I'm sure somebody can come up with a compromise that works for everyone. Assuming this is the issue about e.g. IPNetwork('7.7.7.7/30') != IPNetwork('7.7.7.4/30') even though these describe the same network (and in fact their .network and .broadcast attributes have the same values), there are several compromises; I don't know the use cases well enough to pick one: - There could be an optional keyword parameter that decides whether the last bits are cleared or not (one would have to argue which behavior to use by default). - The __eq__ (and hence __hash__) could be made to return equality even though the .ip attribute returns a different value and the repr() is different. This is not unheard-of; Python's __eq__ is best thought of as some sort of equivalence. For example two dicts that only differ in the order of the items still compare equal (even though .keys() and repr() return different values). I note that it's easy to convert the unnormalized form to the normalized form: a = IPNetwork('7.7.7.7/30') b = IPNetwork(a.network, a.prefixlen) It would also be easy to have a property or method that returns the normalized version; as an optimization it could return self if self is already normalized. And there could be an explicit API to test whether a network is normalized (something more explicit than a.network == a.ip). I'll leave it to others to discuss the pros and cons of each alternative. I don't know why Peter wants to preserve the unnormalized data but I'm sure he has a good use case, otherwise he wouldn't be so adamant to keep it. :-) -- --Guido van Rossum (home page: http://www.python.org/~guido/)
On Tue, 29 Sep 2009 02:39:06 am Guido van Rossum wrote:
I think Peter is pretty frustrated by the many attacks on "his" library. There are probably a number of different things going on simultaneous: Peter has been driven into the defense by attacks both reasonable and unreasonable, there have been misunderstandings all around, teasing out use cases (by both parties) has been a problem.
As one of those people who has been critical of parts of Peter's module, I'd like to publicly say that I *mostly* like it. Sometimes we focus too much on the negatives and don't remember to give credit where credit is due. Hopefully we can reach consensus, or at least understanding, on the remaining issue(s). -- Steven D'Aprano
I've never said otherwise. In fact, from an email last night, "If what the community requires is the library you've described, then ipaddr is not that library." The changes *you* require make ipaddr significantly less useful to me. I'm not prepared to make those changes in an attempt seek acceptance to the stdlib, especially if the stdlib is in such flux that I'll get to do this again in 18 months.
The point is that, having brought it to us, we all now have an interest in the outcome. Whatever goes into the standard library is going to be something that we have to live with for a long time, and now is our best chance to shape the result. I understand your concern over introducing more classes, however I still feel my suggested functional decomposition is worth that cost because I consider the behaviour of my suggested classes to be more intuitive. I should mention that I am not a computer scientist, and none of this is motivated by a desire for theoretical purity - just practical experience. One of my concerns now is that if a code block receives an IPv4Network instance, it does not know whether this represents a host address with mask, or a network address. In some contexts, this distinction is critical, and confounding them can result in delayed error reporting or erroneous behaviour. Your addition of a strict flag does not completely address this concern as it assumes the instantiation and use occur in proximity, which is often not the case in large projects. I suspect you are also mistaken in thinking my proposed changes make the module less useful for you - maybe you can describe the problem as you see it? As a reminder to people who have come late to this thread, I proposed three classes per protocol: IPv?Address A single address IPv?AddressWithMask A single address with implied IPv?Network IPv?Network A container-like network address (with strict mask parsing) Further: * Comparisons between classes should be disallowed. * The IPv?AddressWithMask class would have a .address and .mask attributes containing IPv?Addresses, and a .network attribute for the containing network (as specified by the mask, and lazily constructed). * The IPv?Network class would have similar .address and .mask attributes. In cases where you want to allow lax specification of network addresses, this would be spelt: IPv?AddressWithMask(some_address).network At first glance, this seems somewhat round-about, however it makes explicit the potential loss of bits. -- Andrew McNamara, Senior Developer, Object Craft http://www.object-craft.com.au/
On Sun, 27 Sep 2009 at 13:59, Peter Moody wrote:
On Sun, Sep 27, 2009 at 1:49 PM, Antoine Pitrou <solipsis@pitrou.net> wrote:
Peter Moody <peter <at> hda3.com> writes:
def parse_net_and_addr(s): �return (IPNetwork(s), IPAddress(s.split('/')[0]))
I've only heard talk of new classes and new methods, not new constructor functions.
Well, "method" in that context meant "class method" since the results aren't dependent on a particular instance. Of course, both a class method or a module-level function would be fine.
so this is not the response I got when I asked what was required before. Would adding this constructor function satisfy your concerns (given sensible strict settings in the constructor, etc)?
Assuming the Network type loses the notion of a specific host (or host address, or `ip`) attached to it, yes.
this is "less useful (strictly removing functionality)" and is an example of what I explicitly said I was not going to do with ipaddr.
In that case, I vote -1 on the inclusion of ipaddr in the stdlib. --David
Peter Moody wrote:
On Sun, Sep 27, 2009 at 1:49 PM, Antoine Pitrou <solipsis@pitrou.net> wrote:
Assuming the Network type loses the notion of a specific host (or host address, or `ip`) attached to it, yes.
this is "less useful (strictly removing functionality)" and is an example of what I explicitly said I was not going to do with ipaddr.
Would you be kind enough to explain exactly what use case you have for retaining this information? Apologies if you've done so before -- I've been trying to follow this discussion, but that point doesn't seem to have come through clearly. -- Greg
Would you be kind enough to explain exactly what use case you have for retaining this information?
Apologies if you've done so before -- I've been trying to follow this discussion, but that point doesn't seem to have come through clearly. Please don't apologize. It shouldn't matter how many times it's been mentioned on the mailing list. The PEP process is intended to summarize the discussion. A PEP should
On Sun, Sep 27, 2009 at 9:26 PM, Greg Ewing <greg.ewing@canterbury.ac.nz> wrote: pretty much stand alone, with specific external links when necessary. The use case should be added to the PEP.
Peter Moody wrote:
Assuming the Network type loses the notion of a specific host (or host address, or `ip`) attached to it, yes.
this is "less useful (strictly removing functionality)" and is an example of what I explicitly said I was not going to do with ipaddr.
A possible compromise then: Just change the definition of network equality to only consider the network address and ignore the ip attribute. Optionally provide a separate comparison method that pays attention to the ip attribute (keeping in mind that it isn't particularly hard for people to write out "net1 == net2 and net1.ip == net2.ip" if they care about the extra state). Then "IPNetwork" can be largely documented as a true IP network definition, with the "Host with Netmask" use case handled by having an IPNetwork object with "net.ip != net.network". Regards, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia ---------------------------------------------------------------
Peter Moody wrote:
On Sun, Sep 27, 2009 at 1:49 PM, Antoine Pitrou <solipsis@pitrou.net> wrote:
Peter Moody <peter <at> hda3.com> writes:
def parse_net_and_addr(s): return (IPNetwork(s), IPAddress(s.split('/')[0])) I've only heard talk of new classes and new methods, not new constructor functions. Well, "method" in that context meant "class method" since the results aren't dependent on a particular instance. Of course, both a class method or a module-level function would be fine. so this is not the response I got when I asked what was required before. Would adding this constructor function satisfy your concerns (given sensible strict settings in the constructor, etc)? Assuming the Network type loses the notion of a specific host (or host address, or `ip`) attached to it, yes.
this is "less useful (strictly removing functionality)" and is an example of what I explicitly said I was not going to do with ipaddr.
Cheers, /peter
Not that I should have any say, but I'm also -1 on any proposal that conflates an "address with mask" and "network" into the same object. Janzert
Peter Moody wrote:
Steven D'Aprano wrote:
Could you explain what benefit there is for allowing the user to create network objects that don't represent networks? Is there a use-case where these networks-that-aren't-networks are something other than a typo? Under what circumstances would I want to specify a network as 192.168.1.1/24 instead of 192.168.1.0/24?
that pretty flatly states that my use case is invalid.
Looks like Steven was asking you to explain your use case to him rather than stating that it didn't exist. (although I will grant that the network definition use case had been well covered, I will also grant that these threads have been somewhat interminable and I can easily understand someone missing those use case definitions - the example of being able to define a network given only the network mask and the IP address of the host running the current application should be mentioned explicitly in the PEP)
1) if strict=False, mask off the bits described by the netmask when creating an IPNetwork, such that the host bits are always 0.
I haven't heard anyone suggest auto-masking bits, but otherwise that would be strict=True.
Actually, that's exactly what I suggested in this thread - that IPNetwork should lose the "ip" property and that the definition of "network equality" should be based on the network address not on the host address that happened to be used when constructing the network object. The part that is confusing with the current library implementation is the fact that we can have two IPNetwork objects, supposedly describing the same network, compare unequal because they happened to be defined differently. It would be analagous to having "Decimal('3.0') != Decimal('3.00')".
2) add a single new function:
def parse_net_and_addr(s): return (IPNetwork(s), IPAddress(s.split('/')[0]))
I've only heard talk of new classes and new methods, not new constructor functions. In fact, when I asked for explicit clarification of what was required, a new constructor function "ala IPAddress and IPNetwork (so the current classes remain largely the same and the various constructors enforce certain restrictions)", I was told, no, a new object AddressWithMask was actually required. I've no problem with a constructor like this, but this is not what people have been asking for.
No, AddressWithMask was merely defined as a concept separate from an IP Network to indicate how the current IPNetwork class was being overloaded with two distinct concepts and hence exhibiting unnecessary behavioural quirks. The use case for "given a netmask and an arbitrary host on that network, give me the appropriate IPNetwork object" has been well established by this discussion (although still isn't particularly well described even in the latest PEP update). This is what "strict=False" covers, and I'm now happy that practicality means this is appropriate default behaviour for the IPNetwork constructor. The use case for "create an IPNetwork object and have it *remember* which particular host address was used to define it" is still not established at all. It is this latter use case which is covered by the AddressWithMask concept (which may be perfectly validly represented as a simple IPNetwork/IPAddress tuple, which was also mentioned when the concern was first raised). The main concern here is to take the "AddressWithMask" behaviour *off* the IPNetwork objects. It interferes with their interpretation as descriptions of networks because they maintain a piece of irrelevant state and pay attention to it in comparison operations. Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia ---------------------------------------------------------------
Looking though the tests you have setup for ipaddr it is clear that you want the following to be True ip1 = ipaddr.IPv4Network('1.1.1.0/24') ip2 = ipaddr.IPv4Network('1.1.1.1/24') ip1 == ip2 based on this test self.assertEquals(ip1.compare_networks(ip2), 0) but your ><= operators all compare against _ip instead of network. I submitted a patch for review @ http://codereview.appspot.com/124057
Nick Coghlan wrote:
The use case for "given a netmask and an arbitrary host on that network, give me the appropriate IPNetwork object" has been well established by this discussion (although still isn't particularly well described even in the latest PEP update). This is what "strict=False" covers,
I think I'd rather have a separate constructor function or method for this, rather than a somewhat cryptically named boolean parameter. -- Greg
Greg Ewing wrote:
Nick Coghlan wrote:
The use case for "given a netmask and an arbitrary host on that network, give me the appropriate IPNetwork object" has been well established by this discussion (although still isn't particularly well described even in the latest PEP update). This is what "strict=False" covers,
I think I'd rather have a separate constructor function or method for this, rather than a somewhat cryptically named boolean parameter.
Yes, I would prefer a separate method as well. It doesn't bother as much as the broken definition of equality though. In fact, if the definition of IPNetwork equality was fixed then leaving strict mode out entirely would probably be OK. Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia ---------------------------------------------------------------
On Mon, 28 Sep 2009 02:47:27 am Peter Moody wrote:
There was a proposal to have a separate parse_address_and_mask method which would return a (Address, Network) tuple, I still don't know why you don't seem to consider it seriously, rather than trying to make the Network class a kind of all-in-one type conflating different concepts.
The reason (aside from the name) that I'm not going to include this in ipaddr is that it would require the user to deal with two objects when one would suffice. It's similar to getting two return values from float().
integer, fraction = float('1.25')
crazy, right?
Not if you want a separate integer and fraction object. There are plenty of use-cases for such things, and the math module includes a function, modf(), that does precisely that..
Finally, to Stephen's point about seeing the other side of the argument, I wrote this offlist a week ago:
I *understand* what you're saying, I *understand* that 192.168.1.1/24 isn't a network,
But you still want to treat it as one. Could you explain what benefit there is for allowing the user to create network objects that don't represent networks? Is there a use-case where these networks-that-aren't-networks are something other than a typo? Under what circumstances would I want to specify a network as 192.168.1.1/24 instead of 192.168.1.0/24? -- Steven D'Aprano
On Sun, Sep 27, 2009 at 10:30 AM, Steven D'Aprano <steve@pearwood.info> wrote:
On Mon, 28 Sep 2009 02:47:27 am Peter Moody wrote:
There was a proposal to have a separate parse_address_and_mask method which would return a (Address, Network) tuple, I still don't know why you don't seem to consider it seriously, rather than trying to make the Network class a kind of all-in-one type conflating different concepts.
The reason (aside from the name) that I'm not going to include this in ipaddr is that it would require the user to deal with two objects when one would suffice. It's similar to getting two return values from float().
integer, fraction = float('1.25')
crazy, right?
Not if you want a separate integer and fraction object. There are plenty of use-cases for such things, and the math module includes a function, modf(), that does precisely that..
Finally, to Stephen's point about seeing the other side of the argument, I wrote this offlist a week ago:
I *understand* what you're saying, I *understand* that 192.168.1.1/24 isn't a network,
But you still want to treat it as one.
Could you explain what benefit there is for allowing the user to create network objects that don't represent networks? Is there a use-case where these networks-that-aren't-networks are something other than a typo? Under what circumstances would I want to specify a network as 192.168.1.1/24 instead of 192.168.1.0/24?
this is pretty ridiculous. if in the last two months you haven't seen a single use case, then you haven't been paying attention.
-- Steven D'Aprano _______________________________________________ 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, 28 Sep 2009 03:53:27 am Peter Moody wrote:
I *understand* what you're saying, I *understand* that 192.168.1.1/24 isn't a network,
But you still want to treat it as one.
Could you explain what benefit there is for allowing the user to create network objects that don't represent networks? Is there a use-case where these networks-that-aren't-networks are something other than a typo? Under what circumstances would I want to specify a network as 192.168.1.1/24 instead of 192.168.1.0/24?
this is pretty ridiculous. if in the last two months you haven't seen a single use case, then you haven't been paying attention.
No, I haven't read every single email in excruciating detail in this extremely long thread. I'd bet most other people haven't. I'm trying to understand why you want something which, in *my* ignorance, seems patently ridiculous to me: allowing Network objects which aren't Networks, particularly since in private email to me you denied that there was a use-case for the requested (Address object + netmask). But it seems to me that this is exactly what you have in the current implementation, except you call it a Network object, and have rejected the suggestion that the non-network bits of the address should be zeroed. That is, you've rejected the idea of having:
IPv4Network(192.168.1.1/24) IPv4Network(192.168.1.0/24)
as reducing functionality, presumably because the address 192.168.1.1 is lost. Sounds just like an Address+netmask to me, with added network-like behaviour. Some people have requested a way of explicitly calculating a network from an Address and netmask, and you've been hostile to the idea. But it seems to me that your API does exactly that. I'm not the only person who thinks your API conflates two different concepts into a single class, and I'm trying to see your side of the argument. But your hostile attitude isn't making it easy. -- Steven D'Aprano
On Sun, Sep 27, 2009 at 5:13 PM, Steven D'Aprano <steve@pearwood.info> wrote:
On Mon, 28 Sep 2009 03:53:27 am Peter Moody wrote:
I *understand* what you're saying, I *understand* that 192.168.1.1/24 isn't a network,
But you still want to treat it as one.
Could you explain what benefit there is for allowing the user to create network objects that don't represent networks? Is there a use-case where these networks-that-aren't-networks are something other than a typo? Under what circumstances would I want to specify a network as 192.168.1.1/24 instead of 192.168.1.0/24?
this is pretty ridiculous. if in the last two months you haven't seen a single use case, then you haven't been paying attention.
No, I haven't read every single email in excruciating detail in this extremely long thread. I'd bet most other people haven't.
I'm trying to understand why you want something which, in *my* ignorance, seems patently ridiculous to me: allowing Network objects which aren't Networks, particularly since in private email to me you denied that there was a use-case for the requested (Address object + netmask).
no, it seems as though you're either misrepresenting my position or you misunderstood what I said. I said that there wasn't a use-case for explicitly pulling that functionality out into a a new class, and having 6 classes.
But it seems to me that this is exactly what you have in the current implementation, except you call it a Network object, and have rejected the suggestion that the non-network bits of the address should be zeroed.
I have not rejected this. I have rejected the suggestion that the current IPv?Network classes do this by default.
That is, you've rejected the idea of having:
IPv4Network(192.168.1.1/24) IPv4Network(192.168.1.0/24)
yes, I and everyone have rejected that idea. this should either raise an error, or do what it does now, that is, return IPv4Network('192.168.1.1/24')
as reducing functionality, presumably because the address 192.168.1.1 is lost.
good guess.
Sounds just like an Address+netmask to me, with added network-like behaviour.
Some people have requested a way of explicitly calculating a network from an Address and netmask, and you've been hostile to the idea. But it seems to me that your API does exactly that.
You mean the suggestion to include an IPv?Network object attribute with the IPv?Address objects? I thought that was dropped long ago.
I'm not the only person who thinks your API conflates two different concepts into a single class, and I'm trying to see your side of the argument. But your hostile attitude isn't making it easy.
apologies if you find me hostile. I'm not sure how you'd expect me to be if, after 2 months 200+ messages, both on list and off, you were unable to recall a single use-case.
-- Steven D'Aprano _______________________________________________ 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:
That is, you've rejected the idea of having:
IPv4Network(192.168.1.1/24) IPv4Network(192.168.1.0/24)
yes, I and everyone have rejected that idea. this should either raise an error, or do what it does now, that is, return IPv4Network('192.168.1.1/24')
Um, no, several people (me included) have said that defining an IPNetwork based on its *network address* and its netmask, instead of the arbitrary hostname.
as reducing functionality, presumably because the address 192.168.1.1 is lost.
good guess.
Sounds just like an Address+netmask to me, with added network-like behaviour.
Some people have requested a way of explicitly calculating a network from an Address and netmask, and you've been hostile to the idea. But it seems to me that your API does exactly that.
You mean the suggestion to include an IPv?Network object attribute with the IPv?Address objects? I thought that was dropped long ago.
No, we're talking about any way of calculating the canonical network object given a host within that network and the netmask. With the current incarnation of ipaddr, the way you do that is to create an IPNetwork object with net.ip != net.network. But then you get a bizarre artifact, in that the same network will not compare equal if it is derived using a different IP address. There are *3* major concepts in ipaddr: - single address - network (defined by network address + net mask) - arbitrary host associated with a specific network Since those 3 concepts are being mapped to only two classes, 3 different ways have been proposed of handling the 3rd concept: - a "network" attribute on IPAddress objects (rejected, largely by consensus as far as I can tell) - a 2-tuple containing an IPAddress object and an IPNetwork object (rejected implicitly by your refusal to remove the .ip attribute from IPNetwork objects) - the current implementation, which uses an IPNetwork object with net.ip != net.network. That 3rd approach would be largely OK, *except* that the current implementation of it breaks the definition of network equality. Currently, IPNetwork("192.168.1.0/24") != IPNetwork("192.168.1.1/24"), despite the fact that they refer to the exact same network. I believe that is the fundamental point of contention here. Regards, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia ---------------------------------------------------------------
Finally, to Stephen's point about seeing the other side of the argument, I wrote this offlist a week ago:
I *understand* what you're saying, I *understand* that 192.168.1.1/24 isn't a network,
But you still want to treat it as one.
Could you explain what benefit there is for allowing the user to create network objects that don't represent networks? Is there a use-case where these networks-that-aren't-networks are something other than a typo? Under what circumstances would I want to specify a network as 192.168.1.1/24 instead of 192.168.1.0/24?
It's fairly obvious to me why the library should support 192.168.1.1/24 as an input, and return a network. End-users are likely going to enter such things (e.g. 82.94.164.162/29), as they will know one IP address in the network (namely, of one machine that they are looking at), and they will know the prefix length (more often, how large the network is - 8 or 16 or 32). So very clearly, end users should not be required to make the computation in their heads. So Python code has to make the computation, and it seems most natural that the IP library is the piece of code that is able to compute a network out of that input. Does that answer your question? Regards, Martin
Martin v. Löwis <martin <at> v.loewis.de> writes:
Could you explain what benefit there is for allowing the user to create network objects that don't represent networks? Is there a use-case where these networks-that-aren't-networks are something other than a typo? Under what circumstances would I want to specify a network as 192.168.1.1/24 instead of 192.168.1.0/24?
[...]
So Python code has to make the computation, and it seems most natural that the IP library is the piece of code that is able to compute a network out of that input.
The thing is, it doesn't create a network, it creates a hybrid "network plus host" which retains knowledge about the original host (that is, 192.168.1.1 rather than simply 192.168.1.0, if you enter "192.168.1.1/24"). That's what the OP meant with "networks-that-aren't-networks", and that's what people are objecting to. Regards Antoine.
Martin v. Löwis <martin <at> v.loewis.de> writes:
Could you explain what benefit there is for allowing the user to create network objects that don't represent networks? Is there a use-case where these networks-that-aren't-networks are something other than a typo? Under what circumstances would I want to specify a network as 192.168.1.1/24 instead of 192.168.1.0/24?
[...] So Python code has to make the computation, and it seems most natural that the IP library is the piece of code that is able to compute a network out of that input.
The thing is, it doesn't create a network, it creates a hybrid "network plus host" which retains knowledge about the original host (that is, 192.168.1.1 rather than simply 192.168.1.0, if you enter "192.168.1.1/24").
That's what the OP meant with "networks-that-aren't-networks", and that's what people are objecting to.
That's not the question that was asked, though - the question asked was "Under what circumstances would I want to specify...". I hope most people agree that it is desirable to be able to specify a network not just by its network address. Regards, Martin
Martin v. Löwis wrote:
Martin v. Löwis <martin <at> v.loewis.de> writes:
Could you explain what benefit there is for allowing the user to create network objects that don't represent networks? Is there a use-case where these networks-that-aren't-networks are something other than a typo? Under what circumstances would I want to specify a network as 192.168.1.1/24 instead of 192.168.1.0/24?
[...] So Python code has to make the computation, and it seems most natural that the IP library is the piece of code that is able to compute a network out of that input. The thing is, it doesn't create a network, it creates a hybrid "network plus host" which retains knowledge about the original host (that is, 192.168.1.1 rather than simply 192.168.1.0, if you enter "192.168.1.1/24").
That's what the OP meant with "networks-that-aren't-networks", and that's what people are objecting to.
That's not the question that was asked, though - the question asked was "Under what circumstances would I want to specify...". I hope most people agree that it is desirable to be able to specify a network not just by its network address.
I can't help but feel that you and many others jumping on Antoine et al. have skipped reading or only skimmed this topic of discussion. Antoine Pitrou wrote:
We just need a factory function which returns a tuple after parsing:
>>> addr, net = parse_address_with_mask('192.168.1.1/24') >>> addr == IPv4Address('192.168.1.1') True >>> net == IPv4Network('192.168.1.0/24') True
I still back this suggestion. I would also support a "loose=True" flag for the IPNetwork constructor, which would allow host bits to be non-zero. However, I will *never* support a proposal that includes retaining the host address. I believe I am not alone in that. However, Peter has made it quite clear that he will *never* change that about the IPNetwork classes. I would be quite glad to not have ipaddr included in the stdlib. As I can only imagine code that uses it being quite confusing to maintain (e.g., "wait is that actually a network or is that someone using IPNetwork to be an IPAddressWithMask?"). -1. -- Scott Dial scott@scottdial.com scodial@cs.indiana.edu
Le lundi 28 septembre 2009 à 22:11 +0200, "Martin v. Löwis" a écrit :
That's not the question that was asked, though - the question asked was "Under what circumstances would I want to specify...". I hope most people agree that it is desirable to be able to specify a network not just by its network address.
To me it makes no sense to "specify a network not just by its network address", because by definition a prefix + mask is all that characterizes a network: that's all you need to specify it entirely. Adding a "base address" would be like adding a "port number" attribute to the Address class: it's abusing an existing class by adding irrelevant information. I may be mistaken, but it seems to me that, in the IP world, nowhere does such a "network + host" hybrid appear. You find networks (prefix + mask) in routing protocols, and host addresses in applicative protocols.
On Mon, 28 Sep 2009 at 22:32, Antoine Pitrou wrote:
Le lundi 28 septembre 2009 à 22:11 +0200, "Martin v. Löwis" a écrit :
That's not the question that was asked, though - the question asked was "Under what circumstances would I want to specify...". I hope most people agree that it is desirable to be able to specify a network not just by its network address.
To me it makes no sense to "specify a network not just by its network address", because by definition a prefix + mask is all that characterizes a network: that's all you need to specify it entirely. Adding a "base address" would be like adding a "port number" attribute to the Address class: it's abusing an existing class by adding irrelevant information.
I may be mistaken, but it seems to me that, in the IP world, nowhere does such a "network + host" hybrid appear. You find networks (prefix + mask) in routing protocols, and host addresses in applicative protocols.
You do find "address plus mask" when specifying an IP address for an interface. This is a shorthand for specifying the IP address plus the network, since the network can be derived from the IP plus the mask. But it is a _shorthand_, it isn't an entity in its own right. There is no such thing as "a network that has an IP", there is only an _interface configuration_ that has an IP _and_ an associated network. --David
On Mon, 28 Sep 2009 at 22:11, "Martin v. Löwis" wrote:
Martin v. Löwis <martin <at> v.loewis.de> writes:
Could you explain what benefit there is for allowing the user to create network objects that don't represent networks? Is there a use-case where these networks-that-aren't-networks are something other than a typo? Under what circumstances would I want to specify a network as 192.168.1.1/24 instead of 192.168.1.0/24?
[...] So Python code has to make the computation, and it seems most natural that the IP library is the piece of code that is able to compute a network out of that input.
The thing is, it doesn't create a network, it creates a hybrid "network plus host" which retains knowledge about the original host (that is, 192.168.1.1 rather than simply 192.168.1.0, if you enter "192.168.1.1/24").
That's what the OP meant with "networks-that-aren't-networks", and that's what people are objecting to.
That's not the question that was asked, though - the question asked was "Under what circumstances would I want to specify...". I hope most people agree that it is desirable to be able to specify a network not just by its network address.
But then it's not a network, it is an ipaddress-plus-mask. It is exactly that conflation that we are objecting to. There is no question about the use case of _specifying_ a network ip plus a netmask and deriving a network object from that. That is unquestionably required by any useful API. The argument is about whether the object returned is a Network object, or a hybrid object representing _both_ an IP address and a network. It is the latter, which ipaddr does, which many of us find problematic and likely to lead to hard to read programs that will probably produce maintenance errors. I observe that this line in the current PEP rationale: IP addresses and IP networks are distinct. is not in fact achieved by the reference implementation. Peter, however, clearly thinks it is, since it is listed as a design goal of ipaddr. This is a language disconnect I don't understand, which I think has been the source of a lot of the difficulties in this thread. --David
On Mon, Sep 28, 2009 at 1:36 PM, R. David Murray <rdmurray@bitdance.com> wrote:
On Mon, 28 Sep 2009 at 22:11, "Martin v. Löwis" wrote:
Martin v. Löwis <martin <at> v.loewis.de> writes:
Could you explain what benefit there is for allowing the user to create network objects that don't represent networks? Is there a use-case where these networks-that-aren't-networks are something other than a typo? Under what circumstances would I want to specify a network as 192.168.1.1/24 instead of 192.168.1.0/24?
[...]
So Python code has to make the computation, and it seems most natural that the IP library is the piece of code that is able to compute a network out of that input.
The thing is, it doesn't create a network, it creates a hybrid "network plus host" which retains knowledge about the original host (that is, 192.168.1.1 rather than simply 192.168.1.0, if you enter "192.168.1.1/24").
That's what the OP meant with "networks-that-aren't-networks", and that's what people are objecting to.
That's not the question that was asked, though - the question asked was "Under what circumstances would I want to specify...". I hope most people agree that it is desirable to be able to specify a network not just by its network address.
But then it's not a network, it is an ipaddress-plus-mask. It is exactly that conflation that we are objecting to. There is no question about the use case of _specifying_ a network ip plus a netmask and deriving a network object from that. That is unquestionably required by any useful API. The argument is about whether the object returned is a Network object, or a hybrid object representing _both_ an IP address and a network. It is the latter, which ipaddr does, which many of us find problematic and likely to lead to hard to read programs that will probably produce maintenance errors.
I observe that this line in the current PEP rationale:
IP addresses and IP networks are distinct.
is not in fact achieved by the reference implementation. Peter, however, clearly thinks it is, since it is listed as a design goal of ipaddr. This is a language disconnect I don't understand, which I think has been the source of a lot of the difficulties in this thread.
I say the case has been argued extensively, let's wait for Peter to respond. I would say that there certainly are precedents in other areas for keeping the information about the input form around. For example, occasionally it would be handy if parsing a hex integer returned an object that was compatible with other integers but somehow kept a hint that would cause printing it to use hex by default. I see keeping around the IP address used to create a network object as a similar edge case. I would probably define the __eq__ method to implement equivalency (ignoring the form of the input), just as I would in the case of the (hypothetical) hex integers. If you wanted to do a comparison that includes the input IP address, you could use (a, a.ip) == (b, b.ip). -- --Guido van Rossum (home page: http://www.python.org/~guido/)
I would say that there certainly are precedents in other areas for keeping the information about the input form around. For example, occasionally it would be handy if parsing a hex integer returned an object that was compatible with other integers but somehow kept a hint that would cause printing it to use hex by default.
At the risk of bringing in false analogies: it seems that Python typically represents values of some type in their canonical form, rather than remembering the form in which they arrived in the program: - integer values "forget" how many preceding zeroes they have - string literals forget which of the characters had been escaped, and whether the string was single- or double-quoted - floating point values forget a lot more about their literal representation (including even the literal decimal value) I guess a close case would be rational numbers: clearly, 3÷2 == 6÷4; would a Python library still remember (and repr) the original numerator and denominator? Regards, Martin
On Mon, Sep 28, 2009 at 4:29 PM, "Martin v. Löwis" <martin@v.loewis.de>wrote:
I guess a close case would be rational numbers: clearly, 3÷2 == 6÷4; would a Python library still remember (and repr) the original numerator and denominator?
No need for a hypothetical, rational numbers were added in Python 2.6: Python 2.6.2 (r262:71600, Apr 15 2009, 07:20:39) [GCC 3.4.4 (cygming special, gdc 0.12, using dmd 0.125)] on cygwin Type "help", "copyright", "credits" or "license" for more information.
import fractions fractions.Fraction(6,4) Fraction(3, 2)
-- Daniel Stutzbach, Ph.D. President, Stutzbach Enterprises, LLC <http://stutzbachenterprises.com>
Martin v. Löwis wrote:
I would say that there certainly are precedents in other areas for keeping the information about the input form around. For example, occasionally it would be handy if parsing a hex integer returned an object that was compatible with other integers but somehow kept a hint that would cause printing it to use hex by default.
At the risk of bringing in false analogies: it seems that Python typically represents values of some type in their canonical form, rather than remembering the form in which they arrived in the program: - integer values "forget" how many preceding zeroes they have - string literals forget which of the characters had been escaped, and whether the string was single- or double-quoted - floating point values forget a lot more about their literal representation (including even the literal decimal value)
I guess a close case would be rational numbers: clearly, 3÷2 == 6÷4; would a Python library still remember (and repr) the original numerator and denominator?
For a concrete example of an object which remembers details about its creation that it ignores when determining equality, we have decimal.Decimal: .>> from decimal import Decimal as d .>> x = d("3.0") .>> y = d("3.00") .>> x d("3.0") .>> y d("3.00") .>> repr(x) == repr(y) False .>> x.as_tuple() == y.as_tuple() False .>> x == y True (It was actually thinking of this example which led to me suggesting that the equivalence classes of IPNetwork just needed adjusting rather than the .ip attribute being removed completely) Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia ---------------------------------------------------------------
On Wed, Sep 30, 2009 at 1:44 AM, Nick Coghlan <ncoghlan@gmail.com> wrote:
Martin v. Löwis wrote:
I would say that there certainly are precedents in other areas for keeping the information about the input form around. For example, occasionally it would be handy if parsing a hex integer returned an object that was compatible with other integers but somehow kept a hint that would cause printing it to use hex by default.
At the risk of bringing in false analogies: it seems that Python typically represents values of some type in their canonical form, rather than remembering the form in which they arrived in the program: - integer values "forget" how many preceding zeroes they have - string literals forget which of the characters had been escaped, and whether the string was single- or double-quoted - floating point values forget a lot more about their literal representation (including even the literal decimal value)
I guess a close case would be rational numbers: clearly, 3÷2 == 6÷4; would a Python library still remember (and repr) the original numerator and denominator?
For a concrete example of an object which remembers details about its creation that it ignores when determining equality, we have decimal.Decimal:
.>> from decimal import Decimal as d .>> x = d("3.0") .>> y = d("3.00") .>> x d("3.0") .>> y d("3.00") .>> repr(x) == repr(y) False .>> x.as_tuple() == y.as_tuple() False .>> x == y True [snipped]
[More on the Decimal analogy below.] Please could someone who understands the uses of IPNetwork better than I do explain why the following wouldn't be a significant problem, if __eq__ and __hash__ were modified to disregard the .ip attribute as suggested:
linus = IPv4Network('172.16.200.1/24') snoopy = IPv4Network('172.16.200.3/24') fqdn = {linus: 'linus.peanuts.net', snoopy: 'snoopy.peanuts.net'} fqdn[linus] # expecting 'linus.peanuts.net' 'snoopy.peanuts.net'
Is this just a problem of education, teaching the users not to abuse IPv4Network this way? Or is this just an unlikely use of IPv4Network? Or have I misunderstood the proposal altogether? As for Decimal, I see that as another whole kettle of tuna: equality for Decimal couldn't reasonably have been done any other way---if it weren't mandated by the standard, there would still be a very strong expectation that == would mean numeric equality. That is, I see the == operator as having two distinct but mostly compatible uses in Python: it's used for numeric equality, *and* it's used as the equivalence relation for determining container membership. Mostly these two different meanings get along fine, though they lead to some fun when trying to ensure that x == y implies hash(x) == hash(y) for x and y two different numeric types. But since Decimals and floats aren't used as set elements or dict keys that often, the fact that you can't store Decimal('1.0') and Decimal('1.00') together in a set doesn't often get in the way. I'd expect putting IPv4Network objects in a set or dict to be more common. Mark
2009/9/30 Mark Dickinson <dickinsm@gmail.com>:
Please could someone who understands the uses of IPNetwork better than I do explain why the following wouldn't be a significant problem, if __eq__ and __hash__ were modified to disregard the .ip attribute as suggested:
linus = IPv4Network('172.16.200.1/24') snoopy = IPv4Network('172.16.200.3/24') fqdn = {linus: 'linus.peanuts.net', snoopy: 'snoopy.peanuts.net'} fqdn[linus] # expecting 'linus.peanuts.net' 'snoopy.peanuts.net'
I certainly don't understand IPv4Network better than you :-) But that just looks wrong to me - linus and snoopy are hosts not networks, so making them IPv4Network classes seems wrong. I'd instinctively make them IPv4Address objects (which, I believe, would work). Paul.
On Wed, Sep 30, 2009 at 10:52 AM, Paul Moore <p.f.moore@gmail.com> wrote:
2009/9/30 Mark Dickinson <dickinsm@gmail.com>:
Please could someone who understands the uses of IPNetwork better than I do explain why the following wouldn't be a significant problem, if __eq__ and __hash__ were modified to disregard the .ip attribute as suggested:
linus = IPv4Network('172.16.200.1/24') snoopy = IPv4Network('172.16.200.3/24') fqdn = {linus: 'linus.peanuts.net', snoopy: 'snoopy.peanuts.net'} fqdn[linus] # expecting 'linus.peanuts.net' 'snoopy.peanuts.net'
I certainly don't understand IPv4Network better than you :-) But that just looks wrong to me - linus and snoopy are hosts not networks, so making them IPv4Network classes seems wrong. I'd instinctively make them IPv4Address objects (which, I believe, would work).
Okay, so maybe this is an abuse of IPv4Network. But I'd (mis?)understood that the retention of the .ip attribute was precisely a convenience to allow this sort of use. If not, then what's it for? I've read the PEP and almost all of this thread, but I can't help feeling I'm still missing something. If someone could point out the obvious to me I'd be grateful. I don't have any opinion on whether the ip attribute should be retained or not; but retaining it *and* ignoring it in comparisons just seems a bit odd. Mark
Mark Dickinson wrote:
On Wed, Sep 30, 2009 at 10:52 AM, Paul Moore <p.f.moore@gmail.com> wrote:
Please could someone who understands the uses of IPNetwork better than I do explain why the following wouldn't be a significant problem, if __eq__ and __hash__ were modified to disregard the .ip attribute as suggested:
linus = IPv4Network('172.16.200.1/24') snoopy = IPv4Network('172.16.200.3/24') fqdn = {linus: 'linus.peanuts.net', snoopy: 'snoopy.peanuts.net'} fqdn[linus] # expecting 'linus.peanuts.net' 'snoopy.peanuts.net' I certainly don't understand IPv4Network better than you :-) But that just looks wrong to me - linus and snoopy are hosts not networks, so making them IPv4Network classes seems wrong. I'd instinctively make
2009/9/30 Mark Dickinson <dickinsm@gmail.com>: them IPv4Address objects (which, I believe, would work).
Okay, so maybe this is an abuse of IPv4Network. But I'd (mis?)understood that the retention of the .ip attribute was precisely a convenience to allow this sort of use. If not, then what's it for? I've read the PEP and almost all of this thread, but I can't help feeling I'm still missing something. If someone could point out the obvious to me I'd be grateful.
You're not missing anything that I'm aware of - unlike the use case for accepting a denormalised network definition in the IPNetwork constructor (which has been made quite clear in the list discussion, even if it is still a bit vague in the PEP), the use case for *retaining* the host information on the network object hasn't been well articulated at all. The closest anyone has come to describing a use case is an indirect comment via Guido that leaving out the attribute would involve real code having to find somewhere else to stash the original address details (e.g. by passing around an IPAddres/IPNetwork tuple rather than just an IPNetwork object). However, while I'd still be a little happier if the .ip attribute went away all together and another means was found to conveniently associate an IPAddress and an IPNetwork, keeping it doesn't bother me anywhere near as much as having network equivalence defined in terms of something other than the network ID and the netmask. Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia ---------------------------------------------------------------
On Wed, Sep 30, 2009 at 12:06 PM, Nick Coghlan <ncoghlan@gmail.com> wrote:
Mark Dickinson wrote:
Okay, so maybe this is an abuse of IPv4Network. But I'd (mis?)understood that the retention of the .ip attribute was precisely a convenience to allow this sort of use. If not, then what's it for? I've read the PEP and almost all of this thread, but I can't help feeling I'm still missing something. If someone could point out the obvious to me I'd be grateful.
You're not missing anything that I'm aware of - unlike the use case for accepting a denormalised network definition in the IPNetwork constructor (which has been made quite clear in the list discussion, even if it is still a bit vague in the PEP), the use case for *retaining* the host information on the network object hasn't been well articulated at all.
The closest anyone has come to describing a use case is an indirect comment via Guido that leaving out the attribute would involve real code having to find somewhere else to stash the original address details (e.g. by passing around an IPAddres/IPNetwork tuple rather than just an IPNetwork object).
Ah, thanks---I'd missed that bit. So the .ip attribute is mainly for backwards compatibility with existing uses/users of ipaddr. I guess that makes sense, then. In particular, if it's suggested that new code shouldn't make use of the .ip attribute, then the list/dict membership problems described above can't arise.
However, while I'd still be a little happier if the .ip attribute went away all together and another means was found to conveniently associate an IPAddress and an IPNetwork, keeping it doesn't bother me anywhere near as much as having network equivalence defined in terms of something other than the network ID and the netmask.
Makes sense. Thanks, Mark
On Wed, Sep 30, 2009 at 4:33 AM, Mark Dickinson <dickinsm@gmail.com> wrote:
On Wed, Sep 30, 2009 at 12:06 PM, Nick Coghlan <ncoghlan@gmail.com> wrote:
Mark Dickinson wrote:
Okay, so maybe this is an abuse of IPv4Network. But I'd (mis?)understood that the retention of the .ip attribute was precisely a convenience to allow this sort of use. If not, then what's it for? I've read the PEP and almost all of this thread, but I can't help feeling I'm still missing something. If someone could point out the obvious to me I'd be grateful.
You're not missing anything that I'm aware of - unlike the use case for accepting a denormalised network definition in the IPNetwork constructor (which has been made quite clear in the list discussion, even if it is still a bit vague in the PEP), the use case for *retaining* the host information on the network object hasn't been well articulated at all.
The closest anyone has come to describing a use case is an indirect comment via Guido that leaving out the attribute would involve real code having to find somewhere else to stash the original address details (e.g. by passing around an IPAddres/IPNetwork tuple rather than just an IPNetwork object).
Ah, thanks---I'd missed that bit. So the .ip attribute is mainly for backwards compatibility with existing uses/users of ipaddr. I guess that makes sense, then. In particular, if it's suggested that new code shouldn't make use of the .ip attribute, then the list/dict membership problems described above can't arise.
I don't know -- this is (from what Peter told me) a common use case so he (and presumably others) would from time to time have to write extra code to keep track of that IP address in a new app. Since this is just one extra attribute on an IPNetwork object I don't think that adding extra classes which only differ from the IPvXNetwork classes in having this one extra attribute is worthy. -- --Guido van Rossum (home page: http://www.python.org/~guido/)
On Wed, 30 Sep 2009 at 13:11, Guido van Rossum wrote:
On Wed, Sep 30, 2009 at 4:33 AM, Mark Dickinson <dickinsm@gmail.com> wrote:
On Wed, Sep 30, 2009 at 12:06 PM, Nick Coghlan <ncoghlan@gmail.com> wrote:
Mark Dickinson wrote:
Okay, so maybe this is an abuse of IPv4Network. �But I'd (mis?)understood that the retention of the .ip attribute was precisely a convenience to allow this sort of use. �If not, then what's it for? �I've read the PEP and almost all of this thread, but I can't help feeling I'm still missing something. �If someone could point out the obvious to me I'd be grateful.
You're not missing anything that I'm aware of - unlike the use case for accepting a denormalised network definition in the IPNetwork constructor (which has been made quite clear in the list discussion, even if it is still a bit vague in the PEP), the use case for *retaining* the host information on the network object hasn't been well articulated at all.
The closest anyone has come to describing a use case is an indirect comment via Guido that leaving out the attribute would involve real code having to find somewhere else to stash the original address details (e.g. by passing around an IPAddres/IPNetwork tuple rather than just an IPNetwork object).
Ah, thanks---I'd missed that bit. �So the .ip attribute is mainly for backwards compatibility with existing uses/users of ipaddr. �I guess that makes sense, then. �In particular, if it's suggested that new code shouldn't make use of the .ip attribute, then the list/dict membership problems described above can't arise.
I don't know -- this is (from what Peter told me) a common use case so he (and presumably others) would from time to time have to write extra code to keep track of that IP address in a new app. Since this is just one extra attribute on an IPNetwork object I don't think that adding extra classes which only differ from the IPvXNetwork classes in having this one extra attribute is worthy.
I don't believe anyone ever suggested adding a class that differed from IPvXNetwork by the presence or absence of an 'ip' attribute. The two approaches(*) suggested were: 1) do not add another class, just pass around (IPvXAddress, IPVXNetwork) tuples when the address needs to be retained (or write your own tailored trivial class, like I did in my example). 2) add a class that differs from IPvXAddress by having a 'network' attribute that points (possibly lazily) to an IPvXNetwork object, and perhaps 'netmask' and 'hostmask' attributes. Especially after my experience with writing a real example program, I prefer (1). --David (*) For completeness there was also a third approach: add a 'network' attribute to IPvXAddress that would be None if there were no associated netmask. Conceptual problems with this were raised which I won't summarize; IMO it would only be slightly better than IPvXNetwork having an '.ip' attribute.
.On Wed, Sep 30, 2009 at 3:33 PM, R. David Murray <rdmurray@bitdance.com>wrote:
1) do not add another class, just pass around (IPvXAddress, IPVXNetwork) tuples when the address needs to be retained (or write your own tailored trivial class, like I did in my example).
I've been puzzled by objections to forcing the user to decide what metadata to store. Every time I've ever needed to store an IP address or a network, I've always need to store a bunch of other affiliated data with it. E.g.: class GnutellaPeer: # IP address, port, timestamp, and dozen of other fi