Hello community,

here is the log from the commit of package python-ipaddr for openSUSE:Factory 
checked in at 2019-03-26 15:44:42
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-ipaddr (Old)
 and      /work/SRC/openSUSE:Factory/.python-ipaddr.new.25356 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-ipaddr"

Tue Mar 26 15:44:42 2019 rev:18 rq:688251 version:2.2.0

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-ipaddr/python-ipaddr.changes      
2018-12-24 11:38:29.341606672 +0100
+++ /work/SRC/openSUSE:Factory/.python-ipaddr.new.25356/python-ipaddr.changes   
2019-03-26 15:44:52.744117696 +0100
@@ -1,0 +2,10 @@
+Mon Mar 25 12:35:53 UTC 2019 - [email protected]
+
+- version update to 2.2.0
+  * Fix compatibility with Python 3
+    (despite ipaddress existence)
+    https://github.com/google/ipaddr-py/pull/118
+- deleted patches
+  - use_2to3.patch (not needed)
+
+-------------------------------------------------------------------

Old:
----
  ipaddr-2.1.11.tar.gz
  use_2to3.patch

New:
----
  ipaddr-2.2.0.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-ipaddr.spec ++++++
--- /var/tmp/diff_new_pack.zn08Mp/_old  2019-03-26 15:44:53.708116566 +0100
+++ /var/tmp/diff_new_pack.zn08Mp/_new  2019-03-26 15:44:53.712116561 +0100
@@ -1,7 +1,7 @@
 #
 # spec file for package python-ipaddr
 #
-# Copyright (c) 2018 SUSE LINUX GmbH, Nuernberg, Germany.
+# Copyright (c) 2019 SUSE LINUX GmbH, Nuernberg, Germany.
 #
 # All modifications and additions to the file contributed by third parties
 # remain the property of their copyright owners, unless otherwise agreed
@@ -18,19 +18,16 @@
 
 %{?!python_module:%define python_module() python-%{**} python3-%{**}}
 Name:           python-ipaddr
-Version:        2.1.11
+Version:        2.2.0
 Release:        0
 Summary:        Google's IP address manipulation library
 License:        Apache-2.0
 Group:          Development/Languages/Python
 URL:            http://code.google.com/p/ipaddr-py/
 Source:         
https://files.pythonhosted.org/packages/source/i/ipaddr/ipaddr-%{version}.tar.gz
-# PATCH-FIX-OPENSUSE - use_2to3.patch -  use 2to3 to build python3 packages
-Patch0:         use_2to3.patch
 BuildRequires:  %{python_module pkginfo}
 BuildRequires:  %{python_module setuptools}
 BuildRequires:  python-rpm-macros
-BuildRequires:  python3-2to3
 BuildArch:      noarch
 %python_subpackages
 
@@ -41,7 +38,6 @@
 
 %prep
 %setup -q -n ipaddr-%{version}
-%patch0 -p1
 sed -i "1d" ipaddr.py # Fix non-executable script
 
 %build
@@ -51,22 +47,11 @@
 %python_install
 
 %check
-mkdir tester
-pushd tester
-%python_expand cp ../ipaddr_test.py ipaddr_test-%{$python_bin_suffix}.py
-
-if [ -e ipaddr_test-%{python3_bin_suffix}.py ] ; then
-    2to3 -wn ipaddr_test-%{python3_bin_suffix}.py
-fi
-
-%{python_expand export PYTHONPATH=%{buildroot}%{$python_sitelib}
-$python -B ipaddr_test-%{$python_bin_suffix}.py
-}
-popd
+%{python_expand PYTHONPATH=%{buildroot}%{$python_sitelib} $python 
ipaddr_test.py}
 
 %files %{python_files}
 %license COPYING
-%doc README RELEASENOTES
+%doc README
 %{python_sitelib}/*
 
 %changelog

++++++ ipaddr-2.1.11.tar.gz -> ipaddr-2.2.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ipaddr-2.1.11/PKG-INFO new/ipaddr-2.2.0/PKG-INFO
--- old/ipaddr-2.1.11/PKG-INFO  2014-01-31 22:27:22.000000000 +0100
+++ new/ipaddr-2.2.0/PKG-INFO   2017-09-15 20:58:56.000000000 +0200
@@ -1,17 +1,23 @@
 Metadata-Version: 1.1
 Name: ipaddr
-Version: 2.1.11
-Summary: UNKNOWN
-Home-page: http://code.google.com/p/ipaddr-py/
+Version: 2.2.0
+Summary: Google's IP address manipulation library
+Home-page: https://github.com/google/ipaddr-py
 Author: Google
 Author-email: [email protected]
 License: Apache License, Version 2.0
-Description: UNKNOWN
+Description: ipaddr.py is a library for working with IP addresses, both IPv4 
and IPv6.
+        
+        It has been superseded by ipaddress from the Python 3 standard 
library, and its
+        Python 2 backport.
+        
 Platform: UNKNOWN
-Classifier: Development Status :: 5 - Production/Stable
+Classifier: Development Status :: 6 - Mature
 Classifier: Intended Audience :: Developers
 Classifier: License :: OSI Approved :: Apache Software License
 Classifier: Operating System :: OS Independent
+Classifier: Programming Language :: Python
+Classifier: Programming Language :: Python :: 2
 Classifier: Topic :: Internet
 Classifier: Topic :: Software Development :: Libraries
 Classifier: Topic :: System :: Networking
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ipaddr-2.1.11/README new/ipaddr-2.2.0/README
--- old/ipaddr-2.1.11/README    2014-01-31 22:02:24.000000000 +0100
+++ new/ipaddr-2.2.0/README     2017-09-15 20:29:02.000000000 +0200
@@ -1,8 +1,4 @@
 ipaddr.py is a library for working with IP addresses, both IPv4 and IPv6.
-It was developed by Google for internal use, and is now open source.
 
-Project home page: http://code.google.com/p/ipaddr-py/
-
-Please send contributions to [email protected].  Code should
-include unit tests and follow the Google Python style guide:
-http://code.google.com/p/soc/wiki/PythonStyleGuide
+It has been superseded by ipaddress from the Python 3 standard library, and its
+Python 2 backport.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ipaddr-2.1.11/RELEASENOTES 
new/ipaddr-2.2.0/RELEASENOTES
--- old/ipaddr-2.1.11/RELEASENOTES      2014-01-31 22:36:16.000000000 +0100
+++ new/ipaddr-2.2.0/RELEASENOTES       1970-01-01 01:00:00.000000000 +0100
@@ -1,295 +0,0 @@
-#summary notes from releases
-
-= Release Notes =
-
-Here are the visible changes for each release.
-
-== 2.1.11 ==
-
-(2014-01-31)
-
-  * hostmask parsing bug fixed by pmarks (a nearly complete rewrite of the 
mask parsing code)
-  * i97, incorrectly parses some v6 addresses.
-  * docstring typos.
-  * i95, refer to the nets in the exception raised by collapse_address_list
-  * add license to boilerplate to test-2to3.sh
-
-== 2.1.10 ==
-
-(2012-01-20)
-
-Friday night, LAUNCH LAUNCH LAUNCH!
-
-  * i84, fix iterhosts for /31's or /127's
-  * private method arg cleanup.
-  * i83, docstring issue.
-  * i87, new ipv4/ipv6 parser. patch from pmarks
-  * i90, fix copyright.
-  * bytes fix. patch from pmarks.
-           
-== 2.1.9 ==
-
-(2011-02-22)
-
-The last outstanding issues.
-
-  * fix warnings from python3.2
-  * fix bug in _is_shorthand_ip resulting in bad teredo addresses.
-
-== 2.1.8 ==
-
-(2011-02-09)
-
-This release fixes regressions.
-
-  * Address and networks now again compare true, if the address matches.
-  * ipaddr works again on Python 2.4 and 2.5.
-
-== 2.1.7 ==
-
-(2011-01-13)
-
-  * turn teredo and sixtofour into properties as opposed to normal methods.
-
-== 2.1.6 ==
-
-(2011-01-13)
-
-  * typo fixes.
-  * fix for ipaddr_test referring to an old version of ipaddr.
-  * add test cases for r176 and r196.
-  * fix for recognizing IPv6 addresses with embedded IPv4 address not being 
recognized.
-  * additional unit tests for network comparisons and sorting.
-  * force hash() to long to ensure consistency
-  * turn v4_int_to_packed and v6_int_to_packed into public functions to aid 
converting between integers and network objects.
-  * add support for pulling teredo and 6to4 embedded addresses out of an IPv6 
address.
-  
-== 2.1.5 ==
-
-(2010-09-11)
-
-  * containment test should always return false on mixed-type tests.
-
-== 2.1.4 ==
-
-(2010-08-15)
-
-  * fix for issue66, more invalid IPv6 addresses will be rejected
-
-== 2.1.3 ==
-
-(2010-06-12)
-
-  * fix for issue61, incorrect network containment (thanks bw.default)
-  
-== 2.1.2 ==
-
-(2010-05-31)
-
-  * Happy Memorial day.
-  * arithmetic for v4 and v6 address objects and ints (issue 57).
-  * fix address_exclude issue where excluding an address from itself puked.
-  * make sure addresses and networks don't compare.
-  * doc-string fixes (issue60)
-  * and masked() method to _BaseNet to return a network object with the host 
bits masked out (issue58)
-  * fix v6 subnet representation (email to ipaddr-py-dev)
-    
-
-== 2.1.1 ==
-
-(2010-03-02)
-
- * bug with list comprehension in {{{ IPv4Network._is_valid_netmask() }}}
- * kill the last remaining instances of the old exceptions in the 
docstrings(thanks Scott Kitterman)
-
-== 2.1.0 ==
-
-(2010-02-13)
-
-Easier change this time :)
-
-  * networks and addresses are unsortable by default (see 
https://groups.google.com/group/ipaddr-py-dev/browse_thread/thread/8fbc5166be71adbc
 for discussion).
-  * exception text cleanup.
-  * fixing inconsistent behavior of v4/v6 address/network comparisons.
-  * add IPv4Network().is_unspecified (thanks rep.dot.net)
-  * fix for decoding mapped addresses (thanks rlaager)
-  * docstring updates (thanks Scott Kitterman)
-  * fix errant ref to non-existent variable(s) (thanks Harry Bock)
-  * fix exceptions  (most exceptions are subclassed from ValueError now, so 
this can easily be caught)
-  * iterator for looping through subnets (thanks Marco Giutsi)
-
-That's mostly it. there were quite a few other minor changes, but this should 
cover the major bits. Usage.wiki will be updated in the coming days.
-
-== 2.0.0 ==
-
-First and foremost, this is a backwards incompatible change.  Code written for 
ipaddr-1.x will likely not work stock with ipaddr-2.0. For users of the 1.x 
branch, I'll continue to provide support, but new-feature development has 
ceased. But it's not so bad, take a look.All in all, I think this new version 
of ipaddr is much more intuitive and easy to use. 
-
-The best way to get a feel for this code is to download it and try and out, 
but I've tried to list some of the more important changes below to help you out.
-
-The major changes.
-
-  # IPvXAddress and IPvXNetwork classes.
-
-  * Individual addresses are now (IPv4|IPv6)Address objects. Network 
attributes that are actually addresses (eg, broadcast, network, hostmask) are 
now (IPv4|IPv6)Address objects. That means no more IPv4/IPv6 classes handling 
only networks.
-{{{
-In [3]: ipaddr.IPv4Network("1.1.1.0/24")
-Out[3]: IPv4Network('1.1.1.0/24')
-
-In [4]: ipaddr.IPv4Network("1.1.1.0/24").network
-Out[4]: IPv4Address('1.1.1.0')
-
-In [5]: ipaddr.IPv4Network("1.1.1.0/24").broadcast
-Out[5]: IPv4Address('1.1.1.255')
-}}}
-
-  * no more ext methods. To reference the stringified version of any 
attribute, you call str() on (similar for the numeric value with int()).
-{{{
-In [6]: str(ipaddr.IPv4Network("1.1.1.0/24").broadcast)
-Out[6]: '1.1.1.255'
-
-In [7]: int(ipaddr.IPv4Network("1.1.1.0/24").broadcast)
-Out[7]: 16843263
-
-In [8]: int(ipaddr.IPv4Network("1.1.1.0/24").network)
-Out[8]: 16843008
-
-In [9]: str(ipaddr.IPv4Network("1.1.1.0/24").network)
-Out[9]: '1.1.1.0'
-}}}
-
-  * IP() everything-constructor has been replaced by IPAddress() and 
IPNetwork() constructors.  It seems reasonable to assume that an application 
programmer will know when they are dealing strictly with ip addresses vs. 
networks and making this separation de-clutters the code.  IPNetwork still 
assumes a default prefixlength of 32 for IPv4 and 128 for IPv6 if none is 
supplied (just like IP() used to), so when in doubt, you can always use 
IPNetwork.
-{{{
-In [16]: ipaddr.IPNetwork('1.1.1.1')
-Out[16]: IPv4Network('1.1.1.1/32')
-
-In [17]: ipaddr.IPNetwork('1.1.1.1/12')
-Out[17]: IPv4Network('1.1.1.1/12')
-
-In [18]: ipaddr.IPNetwork('::1')
-Out[18]: IPv6Network('::1/128')
-
-In [19]: ipaddr.IPNetwork('::1/64')
-Out[19]: IPv6Network('::1/64')
-}}}
-
-  # Some other (but no less important) bug fixes/improvements:
-
-  * __ contains __ accepts strings/ints as well as (IPv4|IPv6)Address objects.
-{{{
-In [9]: ipaddr.IPAddress('1.1.1.1') in ipaddr.IPNetwork('1.1.1.0/24')
-Out[9]: True
-
-In [10]: '1.1.1.1' in  ipaddr.IPv4Network("1.1.1.0/24")         
-Out[10]: True
-
-In [11]: '1' in ipaddr.IPv4Network("0.0.0.0/0")
-Out[11]: True
-
-In [12]: 1 in ipaddr.IPv4Network("0.0.0.0/0")
-Out[12]: True
-}}}
-  * summarize_address_range. You can now get a list of all of the networks 
between two distinct (IPv4|IPv6)Address'es (results in potentially huge speed 
boosts for address collapsing)
-{{{
-In [14]: ipaddr.summarize_address_range(ipaddr.IPAddress('1.1.0.0'), 
ipaddr.IPAddress('1.1.255.255'))
-Out[14]: [IPv4Network('1.1.0.0/16')]
-
-In [15]: ipaddr.summarize_address_range(ipaddr.IPAddress('1.1.0.0'), 
ipaddr.IPAddress('1.1.255.254'))
-Out[15]: 
-[IPv4Network('1.1.0.0/17'),
- IPv4Network('1.1.128.0/18'),
- IPv4Network('1.1.192.0/19'),
- IPv4Network('1.1.224.0/20'),
- IPv4Network('1.1.240.0/21'),
- IPv4Network('1.1.248.0/22'),
- IPv4Network('1.1.252.0/23'),
- IPv4Network('1.1.254.0/24'),
- IPv4Network('1.1.255.0/25'),
- IPv4Network('1.1.255.128/26'),
- IPv4Network('1.1.255.192/27'),
- IPv4Network('1.1.255.224/28'),
- IPv4Network('1.1.255.240/29'),
- IPv4Network('1.1.255.248/30'),
- IPv4Network('1.1.255.252/31'),
- IPv4Network('1.1.255.254/32')]
-}}}
-
-  * network iterators. the (IPv4|IPv6)Network classes now implement iterators 
to help quickly access each member of a network in sequence:
-{{{
-
-In [24]: for addr in iter(ipaddr.IPNetwork('1.1.1.1/28')): addr
-   ....: 
-Out[24]: IPv4Address('1.1.1.0')
-Out[24]: IPv4Address('1.1.1.1')
-Out[24]: IPv4Address('1.1.1.2')
-Out[24]: IPv4Address('1.1.1.3')
-Out[24]: IPv4Address('1.1.1.4')
-Out[24]: IPv4Address('1.1.1.5')
-Out[24]: IPv4Address('1.1.1.6')
-Out[24]: IPv4Address('1.1.1.7')
-Out[24]: IPv4Address('1.1.1.8')
-Out[24]: IPv4Address('1.1.1.9')
-Out[24]: IPv4Address('1.1.1.10')
-Out[24]: IPv4Address('1.1.1.11')
-Out[24]: IPv4Address('1.1.1.12')
-Out[24]: IPv4Address('1.1.1.13')
-Out[24]: IPv4Address('1.1.1.14')
-Out[24]: IPv4Address('1.1.1.15')
-}}}
-
-  * additionally, an iterhosts() method has been added to allow for iterating 
over all of the usable addresses on a network (everything except the network 
and broadcast addresses)
-{{{
-In [26]: for addr in ipaddr.IPNetwork('1.1.1.1/28').iterhosts(): addr
-   ....: 
-Out[26]: IPv4Address('1.1.1.1')
-Out[26]: IPv4Address('1.1.1.2')
-Out[26]: IPv4Address('1.1.1.3')
-Out[26]: IPv4Address('1.1.1.4')
-Out[26]: IPv4Address('1.1.1.5')
-Out[26]: IPv4Address('1.1.1.6')
-Out[26]: IPv4Address('1.1.1.7')
-Out[26]: IPv4Address('1.1.1.8')
-Out[26]: IPv4Address('1.1.1.9')
-Out[26]: IPv4Address('1.1.1.10')
-Out[26]: IPv4Address('1.1.1.11')
-Out[26]: IPv4Address('1.1.1.12')
-Out[26]: IPv4Address('1.1.1.13')
-Out[26]: IPv4Address('1.1.1.14')
-}}}
-
-Thanks to the python community and everyone who's made feature suggestions or 
submitted patches. Please continue to send bugs/enhancements/patches to the 
mailing list.
-
-== 1.1.1 ==
-
-This release contains a single important bugfix.  All users of 1.1.0 should 
upgrade.
-
-  * r77 A logical error caused ordering operators to behave incorrectly.
-
-== 1.1.0 ==
-
-`ipaddr.py` is now part of the standard library in Python 2.7 and 3.1!  This 
release is compatible with the `ipaddr` from future versions of Python.
-
-Special thanks to Philipp Hagemeister for making most of the improvements to 
this release, and to Gregory P. Smith for shepherding this into the Python 
standard library.
-
-  * r59 Method names are now PEP-8 compliant, instead of Google-style camel 
case.  The old method names remain, but are deprecated; you should use the 
lowercase names to be compatible with Python 2.7/3.1. (pmoody)
-  * r63 .prefixlen is now a property. (pmoody)
-  * r64 Stronger validation. (Philipp Hagemeister)
-  * r65 1.2.3.4 is not a valid v6 address, so we can simplify the constructor. 
(Philipp Hagemeister)
-  * r66 Expand rich comparison operations and their tests, with a goal of 
supporting 2to3.  Add a new method .networks_key().  Add a new script to run 
through 2to3 and make sure tests pass under Python 3 with the converted 
version. (Philipp Hagemeister)
-  * r68 New method .packed(). (Philipp Hagemeister)
-  * r69 Add `is_multicast`, `is_unspecified`, `is_loopback`, `is_link_local`, 
`is_site_local`, and `is_private` for IPv6. Make more methods into properties. 
Improved documentation and tests for `is_*` properties for IPv4 and IPv6. 
Rename `networks_key()` to `_get_networks_key()`.
-  * r71 Fix off-by-one bug (issue 15). (gpsmith)
-
-== 1.0.2 ==
-  * r52 Force the return value in testHexRepresentation to uppercase to 
workaround Python version. (smart)
-  * r51 Fix testHexRepresentation().  Hex representations of longs are 
uppercase. (smart)
-  * r50 Remove trailing whitespace and update docstrings. (smart)
-  * r44. this makes the spacing and docstrings pep8 compliant. (pmoody)
-  * r43. When processing the IPv4 mapped address 16 bits at a time, the 
components are stored in the reverse order.  Updated the test to use a 
non-symmetric IPv4 address, which exhibited the bug. (smart)
-  * r40. implment __int__ and __hex__. will need to be updated for py3k (to 
use __index__) (pmoody)
-  * r38 A cleanup from  issue 9 : Make exception messages consistent for 
IP(''), IPv4(''), IPv6('') (smart)
-  * r37 Fix for  issue 9 : ipaddr.IP('') should raise ValueError (mshields)
-
-== 1.0.1 ==
-
-  * str() now produces lowercase for IPv6 addresses, to match inet_pton(3). 
(http://codereview.appspot.com/7678)
-  * repr() now produces strings that can be pasted back into the interpreter.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ipaddr-2.1.11/ipaddr.py new/ipaddr-2.2.0/ipaddr.py
--- old/ipaddr-2.1.11/ipaddr.py 2014-01-31 22:22:32.000000000 +0100
+++ new/ipaddr-2.2.0/ipaddr.py  2017-09-15 20:35:54.000000000 +0200
@@ -22,9 +22,14 @@
 
 """
 
-__version__ = '2.1.11'
+__version__ = '2.2.0'
 
 import struct
+import sys
+
+if sys.version_info > (3,):
+    long = int
+    xrange = range
 
 IPV4LENGTH = 32
 IPV6LENGTH = 128
@@ -156,16 +161,19 @@
         addresses: a list of IPv4 or IPv6 addresses.
 
     Returns:
-        A tuple containing the first and last IP addresses in the sequence.
+        A tuple containing the first and last IP addresses in the sequence,
+        and the index of the last IP address in the sequence.
 
     """
     first = last = addresses[0]
+    last_index = 0
     for ip in addresses[1:]:
         if ip._ip == last._ip + 1:
             last = ip
+            last_index += 1
         else:
             break
-    return (first, last)
+    return (first, last, last_index)
 
 def _get_prefix_length(number1, number2, bits):
     """Get the number of leading bits that are same for two numbers.
@@ -358,8 +366,8 @@
     nets = sorted(set(nets))
 
     while i < len(ips):
-        (first, last) = _find_address_range(ips[i:])
-        i = ips.index(last) + 1
+        (first, last, last_index) = _find_address_range(ips[i:])
+        i += last_index + 1
         addrs.extend(summarize_address_range(first, last))
 
     return _collapse_address_list_recursive(sorted(
@@ -876,6 +884,26 @@
         else:
             raise NetmaskValueError('Bit pattern does not match /1*0*/')
 
+    def _prefix_from_prefix_int(self, prefixlen):
+        """Validate and return a prefix length integer.
+
+        Args:
+            prefixlen: An integer containing the prefix length.
+
+        Returns:
+            The input, possibly converted from long to int.
+
+        Raises:
+            NetmaskValueError: If the input is not an integer, or out of range.
+        """
+        if not isinstance(prefixlen, (int, long)):
+            raise NetmaskValueError('%r is not an integer' % prefixlen)
+        prefixlen = int(prefixlen)
+        if not (0 <= prefixlen <= self._max_prefixlen):
+            raise NetmaskValueError('%d is not a valid prefix length' %
+                                    prefixlen)
+        return prefixlen
+
     def _prefix_from_prefix_string(self, prefixlen_str):
         """Turn a prefix length string into an integer.
 
@@ -893,12 +921,10 @@
             if not _BaseV4._DECIMAL_DIGITS.issuperset(prefixlen_str):
                 raise ValueError
             prefixlen = int(prefixlen_str)
-            if not (0 <= prefixlen <= self._max_prefixlen):
-               raise ValueError
         except ValueError:
             raise NetmaskValueError('%s is not a valid prefix length' %
                                     prefixlen_str)
-        return prefixlen
+        return self._prefix_from_prefix_int(prefixlen)
 
     def _prefix_from_ip_string(self, ip_str):
         """Turn a netmask/hostmask string into a prefix length.
@@ -1239,6 +1265,11 @@
         """
         _BaseV4.__init__(self, address)
 
+        # Efficient copy constructor.
+        if isinstance(address, IPv4Address):
+            self._ip = address._ip
+            return
+
         # Efficient constructor from integer.
         if isinstance(address, (int, long)):
             self._ip = address
@@ -1279,29 +1310,32 @@
         """Instantiate a new IPv4 network object.
 
         Args:
-            address: A string or integer representing the IP [& network].
-              '192.168.1.1/24'
-              '192.168.1.1/255.255.255.0'
-              '192.168.1.1/0.0.0.255'
-              are all functionally the same in IPv4. Similarly,
-              '192.168.1.1'
-              '192.168.1.1/255.255.255.255'
-              '192.168.1.1/32'
-              are also functionaly equivalent. That is to say, failing to
-              provide a subnetmask will create an object with a mask of /32.
-
-              If the mask (portion after the / in the argument) is given in
-              dotted quad form, it is treated as a netmask if it starts with a
-              non-zero field (e.g. /255.0.0.0 == /8) and as a hostmask if it
-              starts with a zero field (e.g. 0.255.255.255 == /8), with the
-              single exception of an all-zero mask which is treated as a
-              netmask == /0. If no mask is given, a default of /32 is used.
+            address: The IPv4 network as a string, 2-tuple, or any format
+              supported by the IPv4Address constructor.
 
-              Additionally, an integer can be passed, so
-              IPv4Network('192.168.1.1') == IPv4Network(3232235777).
-              or, more generally
-              IPv4Network(int(IPv4Network('192.168.1.1'))) ==
-                IPv4Network('192.168.1.1')
+              Strings typically use CIDR format, such as '192.0.2.0/24'.
+              If a dotted-quad is provided after the '/', it is treated as
+              a netmask if it starts with a nonzero bit (e.g. 255.0.0.0 == /8)
+              or a hostmask if it starts with a zero bit
+              (e.g. /0.0.0.255 == /8), with the single exception of an all-zero
+              mask which is treated as /0.
+
+              The 2-tuple format consists of an (ip, prefixlen), where ip is 
any
+              format recognized by the IPv4Address constructor, and prefixlen 
is
+              an integer from 0 through 32.
+
+              A plain IPv4 address (in any format) will be forwarded to the
+              IPv4Address constructor, with an implied prefixlen of 32.
+
+              For example, the following inputs are equivalent:
+                IPv4Network('192.0.2.1/32')
+                IPv4Network('192.0.2.1/255.255.255.255')
+                IPv4Network('192.0.2.1')
+                IPv4Network(0xc0000201)
+                IPv4Network(IPv4Address('192.0.2.1'))
+                IPv4Network(('192.0.2.1', 32))
+                IPv4Network((0xc0000201, 32))
+                IPv4Network((IPv4Address('192.0.2.1'), 32))
 
             strict: A boolean. If true, ensure that we have been passed
               A true network address, eg, 192.168.1.0/24 and not an
@@ -1318,41 +1352,51 @@
         _BaseNet.__init__(self, address)
         _BaseV4.__init__(self, address)
 
-        # Constructing from an integer or packed bytes.
-        if isinstance(address, (int, long, Bytes)):
+        # Constructing from a single IP address.
+        if isinstance(address, (int, long, Bytes, IPv4Address)):
             self.ip = IPv4Address(address)
             self._ip = self.ip._ip
             self._prefixlen = self._max_prefixlen
             self.netmask = IPv4Address(self._ALL_ONES)
             return
 
-        # Assume input argument to be string or any object representation
-        # which converts into a formatted IP prefix string.
-        addr = str(address).split('/')
+        # Constructing from an (ip, prefixlen) tuple.
+        if isinstance(address, tuple):
+            try:
+                ip, prefixlen = address
+            except ValueError:
+                raise AddressValueError(address)
+            self.ip = IPv4Address(ip)
+            self._ip = self.ip._ip
+            self._prefixlen = self._prefix_from_prefix_int(prefixlen)
 
-        if len(addr) > 2:
-            raise AddressValueError(address)
+        else:
+            # Assume input argument to be string or any object representation
+            # which converts into a formatted IP prefix string.
+            addr = str(address).split('/')
 
-        self._ip = self._ip_int_from_string(addr[0])
-        self.ip = IPv4Address(self._ip)
+            if len(addr) > 2:
+                raise AddressValueError(address)
 
-        if len(addr) == 2:
-            try:
-                # Check for a netmask in prefix length form.
-                self._prefixlen = self._prefix_from_prefix_string(addr[1])
-            except NetmaskValueError:
-                # Check for a netmask or hostmask in dotted-quad form.
-                # This may raise NetmaskValueError.
-                self._prefixlen = self._prefix_from_ip_string(addr[1])
-        else:
-            self._prefixlen = self._max_prefixlen
+            self._ip = self._ip_int_from_string(addr[0])
+            self.ip = IPv4Address(self._ip)
+
+            if len(addr) == 2:
+                try:
+                    # Check for a netmask in prefix length form.
+                    self._prefixlen = self._prefix_from_prefix_string(addr[1])
+                except NetmaskValueError:
+                    # Check for a netmask or hostmask in dotted-quad form.
+                    # This may raise NetmaskValueError.
+                    self._prefixlen = self._prefix_from_ip_string(addr[1])
+            else:
+                self._prefixlen = self._max_prefixlen
 
         self.netmask = IPv4Address(self._ip_int_from_prefix(self._prefixlen))
 
         if strict:
             if self.ip != self.network:
-                raise ValueError('%s has host bits set' %
-                                 self.ip)
+                raise ValueError('%s has host bits set' % self.ip)
         if self._prefixlen == (self._max_prefixlen - 1):
             self.iterhosts = self.__iter__
 
@@ -1447,7 +1491,7 @@
 
         try:
             # Now, parse the hextets into a 128-bit integer.
-            ip_int = 0L
+            ip_int = long(0)
             for i in xrange(parts_hi):
                 ip_int <<= 16
                 ip_int |= self._parse_hextet(parts[i])
@@ -1752,6 +1796,11 @@
         """
         _BaseV6.__init__(self, address)
 
+        # Efficient copy constructor.
+        if isinstance(address, IPv6Address):
+            self._ip = address._ip
+            return
+
         # Efficient constructor from integer.
         if isinstance(address, (int, long)):
             self._ip = address
@@ -1771,9 +1820,6 @@
         # Assume input argument to be string or any object representation
         # which converts into a formatted IP string.
         addr_str = str(address)
-        if not addr_str:
-            raise AddressValueError('')
-
         self._ip = self._ip_int_from_string(addr_str)
 
 
@@ -1793,28 +1839,34 @@
 
 
     def __init__(self, address, strict=False):
-        """Instantiate a new IPv6 Network object.
+        """Instantiate a new IPv6 network object.
 
         Args:
-            address: A string or integer representing the IPv6 network or the 
IP
-              and prefix/netmask.
-              '2001:4860::/128'
-              '2001:4860:0000:0000:0000:0000:0000:0000/128'
-              '2001:4860::'
-              are all functionally the same in IPv6.  That is to say,
-              failing to provide a subnetmask will create an object with
-              a mask of /128.
+            address: The IPv6 network as a string, 2-tuple, or any format
+              supported by the IPv6Address constructor.
 
-              Additionally, an integer can be passed, so
-              IPv6Network('2001:4860::') ==
-                IPv6Network(42541956101370907050197289607612071936L).
-              or, more generally
-              IPv6Network(IPv6Network('2001:4860::')._ip) ==
-                IPv6Network('2001:4860::')
+              Strings should be in CIDR format, such as '2001:db8::/32'.
+
+              The 2-tuple format consists of an (ip, prefixlen), where ip is 
any
+              format recognized by the IPv6Address constructor, and prefixlen 
is
+              an integer from 0 through 128.
+
+              A plain IPv6 address (in any format) will be forwarded to the
+              IPv6Address constructor, with an implied prefixlen of 128.
+
+              For example, the following inputs are equivalent:
+                IPv6Network('2001:db8::/128')
+                IPv6Network('2001:db8:0:0:0:0:0:0/128')
+                IPv6Network('2001:db8::')
+                IPv6Network(0x20010db8 << 96)
+                IPv6Network(IPv6Address('2001:db8::'))
+                IPv6Network(('2001:db8::', 128))
+                IPv6Network((0x20010db8 << 96, 128))
+                IPv6Network((IPv6Address('2001:db8::'), 128))
 
             strict: A boolean. If true, ensure that we have been passed
-              A true network address, eg, 192.168.1.0/24 and not an
-              IP address on a network, eg, 192.168.1.1/24.
+              A true network address, eg, 2001:db8::/32 and not an
+              IP address on a network, eg, 2001:db8::1/32.
 
         Raises:
             AddressValueError: If address isn't a valid IPv6 address.
@@ -1827,29 +1879,40 @@
         _BaseNet.__init__(self, address)
         _BaseV6.__init__(self, address)
 
-        # Constructing from an integer or packed bytes.
-        if isinstance(address, (int, long, Bytes)):
+        # Constructing from a single IP address.
+        if isinstance(address, (int, long, Bytes, IPv6Address)):
             self.ip = IPv6Address(address)
             self._ip = self.ip._ip
             self._prefixlen = self._max_prefixlen
             self.netmask = IPv6Address(self._ALL_ONES)
             return
 
-        # Assume input argument to be string or any object representation
-        # which converts into a formatted IP prefix string.
-        addr = str(address).split('/')
+        # Constructing from an (ip, prefixlen) tuple.
+        if isinstance(address, tuple):
+            try:
+                ip, prefixlen = address
+            except ValueError:
+                raise AddressValueError(address)
+            self.ip = IPv6Address(ip)
+            self._ip = self.ip._ip
+            self._prefixlen = self._prefix_from_prefix_int(prefixlen)
+
+        else:
+            # Assume input argument to be string or any object representation
+            # which converts into a formatted IP prefix string.
+            addr = str(address).split('/')
 
-        if len(addr) > 2:
-            raise AddressValueError(address)
+            if len(addr) > 2:
+                raise AddressValueError(address)
 
-        self._ip = self._ip_int_from_string(addr[0])
-        self.ip = IPv6Address(self._ip)
+            self._ip = self._ip_int_from_string(addr[0])
+            self.ip = IPv6Address(self._ip)
 
-        if len(addr) == 2:
-            # This may raise NetmaskValueError
-            self._prefixlen = self._prefix_from_prefix_string(addr[1])
-        else:
-            self._prefixlen = self._max_prefixlen
+            if len(addr) == 2:
+                # This may raise NetmaskValueError
+                self._prefixlen = self._prefix_from_prefix_string(addr[1])
+            else:
+                self._prefixlen = self._max_prefixlen
 
         self.netmask = IPv6Address(self._ip_int_from_prefix(self._prefixlen))
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ipaddr-2.1.11/ipaddr_test.py 
new/ipaddr-2.2.0/ipaddr_test.py
--- old/ipaddr-2.1.11/ipaddr_test.py    2014-01-31 22:02:28.000000000 +0100
+++ new/ipaddr-2.2.0/ipaddr_test.py     2017-09-15 02:18:44.000000000 +0200
@@ -17,10 +17,15 @@
 
 """Unittest for ipaddr module."""
 
-
-import unittest
+import pickle
 import time
+import unittest
+
 import ipaddr
+import sys
+
+if sys.version_info > (3,):
+    long = int
 
 # Compatibility function to cast str to bytes objects
 if issubclass(ipaddr.Bytes, str):
@@ -158,6 +163,14 @@
         self.assertRaises(ipaddr.AddressValueError,
                           ipaddr.IPv4Address(1)._ip_int_from_string,
                           '1.a.2.3')
+        self.assertRaises(ipaddr.AddressValueError, ipaddr.IPv4Network,
+                          ('1.2.3.0',))
+        self.assertRaises(ipaddr.AddressValueError, ipaddr.IPv6Network,
+                          ('2001:db8::',))
+        self.assertRaises(ipaddr.AddressValueError, ipaddr.IPv4Network,
+                          ('1.2.3.0', 24, 0))
+        self.assertRaises(ipaddr.AddressValueError, ipaddr.IPv6Network,
+                          ('2001:db8::', 32, 0))
 
     def testGetNetwork(self):
         self.assertEqual(int(self.ipv4.network), 16909056)
@@ -266,7 +279,7 @@
                          '2001:658:22a:cafe:200::1')
 
     def testGetNetmask(self):
-        self.assertEqual(int(self.ipv4.netmask), 4294967040L)
+        self.assertEqual(int(self.ipv4.netmask), 4294967040)
         self.assertEqual(str(self.ipv4.netmask), '255.255.255.0')
         self.assertEqual(str(self.ipv4_hostmask.netmask), '255.0.0.0')
         self.assertEqual(int(self.ipv6.netmask),
@@ -283,7 +296,7 @@
         self.assertEqual(ipv6_zero_netmask._prefix_from_prefix_string('0'), 0)
 
     def testGetBroadcast(self):
-        self.assertEqual(int(self.ipv4.broadcast), 16909311L)
+        self.assertEqual(int(self.ipv4.broadcast), 16909311)
         self.assertEqual(str(self.ipv4.broadcast), '1.2.3.255')
 
         self.assertEqual(int(self.ipv6.broadcast),
@@ -443,6 +456,13 @@
             net = ipaddr.IPv4Network(net_str)
             self.assertEqual(str(net), net_str)
 
+            # Parse some 2-tuple inputs.
+            self.assertEqual(str(ipaddr.IPv4Network((0, i))), net_str)
+            self.assertEqual(str(ipaddr.IPv4Network(('0.0.0.0', i))), net_str)
+            self.assertEqual(
+                str(ipaddr.IPv4Network((ipaddr.IPAddress('0.0.0.0'), i))),
+                net_str)
+
             # Generate and re-parse the expanded netmask.
             self.assertEqual(
                 str(ipaddr.IPv4Network('0.0.0.0/%s' % net.netmask)),
@@ -470,6 +490,13 @@
             net_str = '::/%d' % i
             self.assertEqual(str(ipaddr.IPv6Network(net_str)), net_str)
 
+            # Parse some 2-tuple inputs.
+            self.assertEqual(str(ipaddr.IPv6Network((0, i))), net_str)
+            self.assertEqual(str(ipaddr.IPv6Network(('::', i))), net_str)
+            self.assertEqual(
+                str(ipaddr.IPv6Network((ipaddr.IPAddress('::'), i))),
+                net_str)
+
             # Zero prefix is treated as decimal.
             self.assertEqual(str(ipaddr.IPv6Network('::/0%d' % i)), net_str)
 
@@ -479,12 +506,16 @@
         self.assertRaises(ipaddr.NetmaskValueError,
                           ipaddr.IPv4Network, '1.2.3.4/-1')
         self.assertRaises(ipaddr.NetmaskValueError,
+                          ipaddr.IPv4Network, ('1.2.3.4', -1))
+        self.assertRaises(ipaddr.NetmaskValueError,
                           ipaddr.IPv4Network, '1.2.3.4/+1')
         self.assertRaises(ipaddr.NetmaskValueError,
                           ipaddr.IPv4Network, '1.2.3.4/0x1')
         self.assertRaises(ipaddr.NetmaskValueError,
                           ipaddr.IPv4Network, '1.2.3.4/33')
         self.assertRaises(ipaddr.NetmaskValueError,
+                          ipaddr.IPv4Network, ('1.2.3.4', 33))
+        self.assertRaises(ipaddr.NetmaskValueError,
                           ipaddr.IPv4Network, '1.2.3.4/254.254.255.256')
         self.assertRaises(ipaddr.NetmaskValueError,
                           ipaddr.IPv4Network, '1.1.1.1/240.255.0.0')
@@ -501,16 +532,43 @@
         self.assertRaises(ipaddr.NetmaskValueError,
                           ipaddr.IPv6Network, '::1/-1')
         self.assertRaises(ipaddr.NetmaskValueError,
+                          ipaddr.IPv6Network, ('::1', -1))
+        self.assertRaises(ipaddr.NetmaskValueError,
                           ipaddr.IPv6Network, '::1/+1')
         self.assertRaises(ipaddr.NetmaskValueError,
                           ipaddr.IPv6Network, '::1/0x1')
         self.assertRaises(ipaddr.NetmaskValueError,
                           ipaddr.IPv6Network, '::1/129')
         self.assertRaises(ipaddr.NetmaskValueError,
+                          ipaddr.IPv6Network, ('::1', 129))
+        self.assertRaises(ipaddr.NetmaskValueError,
                           ipaddr.IPv6Network, '::1/1.2.3.4')
         # IPv6 expanded form is currently not supported.
         self.assertRaises(ipaddr.NetmaskValueError,
                           ipaddr.IPv6Network, '::/::')
+        # The 2-tuple constructors only accept integer prefixlens for now.
+        self.assertRaises(ipaddr.NetmaskValueError, ipaddr.IPv4Network,
+                          ('0.0.0.0', '0'))
+        self.assertRaises(ipaddr.NetmaskValueError, ipaddr.IPv6Network,
+                          ('::', '0'))
+
+    def testCopyConstructors(self):
+        # Create address types with unparseable str() outputs, to ensure that
+        # the copy constructors aren't taking the slow path.
+        class BadStringIPv4Address(ipaddr.IPv4Address):
+            def __str__(self):
+                return "<IPv4>"
+        class BadStringIPv6Address(ipaddr.IPv6Address):
+            def __str__(self):
+                return "<IPv6>"
+
+        v4addr = BadStringIPv4Address('1.2.3.4')
+        self.assertEqual("<IPv4>", str(v4addr))
+        self.assertEqual(v4addr, ipaddr.IPv4Address(v4addr))
+
+        v6addr = BadStringIPv6Address('2001:db8::')
+        self.assertEqual("<IPv6>", str(v6addr))
+        self.assertEqual(v6addr, ipaddr.IPv6Address(v6addr))
 
     def testNth(self):
         self.assertEqual(str(self.ipv4[5]), '1.2.3.5')
@@ -773,7 +831,12 @@
     def testStrictNetworks(self):
         self.assertRaises(ValueError, ipaddr.IPNetwork, '192.168.1.1/24',
                           strict=True)
-        self.assertRaises(ValueError, ipaddr.IPNetwork, '::1/120', strict=True)
+        self.assertRaises(ValueError, ipaddr.IPNetwork, ('192.168.1.1', 24),
+                          strict=True)
+        self.assertRaises(ValueError, ipaddr.IPNetwork, '::1/120',
+                          strict=True)
+        self.assertRaises(ValueError, ipaddr.IPNetwork, ('::1', 120),
+                          strict=True)
 
     def testOverlaps(self):
         other = ipaddr.IPv4Network('1.2.3.0/30')
@@ -1100,9 +1163,9 @@
 
     def testNetworkElementCaching(self):
         # V4 - make sure we're empty
-        self.assertFalse(self.ipv4._cache.has_key('network'))
-        self.assertFalse(self.ipv4._cache.has_key('broadcast'))
-        self.assertFalse(self.ipv4._cache.has_key('hostmask'))
+        self.assertFalse('network' in self.ipv4._cache)
+        self.assertFalse('broadcast' in self.ipv4._cache)
+        self.assertFalse('hostmask' in self.ipv4._cache)
 
         # V4 - populate and test
         self.assertEqual(self.ipv4.network, ipaddr.IPv4Address('1.2.3.0'))
@@ -1110,14 +1173,14 @@
         self.assertEqual(self.ipv4.hostmask, ipaddr.IPv4Address('0.0.0.255'))
 
         # V4 - check we're cached
-        self.assertTrue(self.ipv4._cache.has_key('network'))
-        self.assertTrue(self.ipv4._cache.has_key('broadcast'))
-        self.assertTrue(self.ipv4._cache.has_key('hostmask'))
+        self.assertTrue('network' in self.ipv4._cache)
+        self.assertTrue('broadcast' in self.ipv4._cache)
+        self.assertTrue('hostmask' in self.ipv4._cache)
 
         # V6 - make sure we're empty
-        self.assertFalse(self.ipv6._cache.has_key('network'))
-        self.assertFalse(self.ipv6._cache.has_key('broadcast'))
-        self.assertFalse(self.ipv6._cache.has_key('hostmask'))
+        self.assertFalse('network' in self.ipv6._cache)
+        self.assertFalse('broadcast' in self.ipv6._cache)
+        self.assertFalse('hostmask' in self.ipv6._cache)
 
         # V6 - populate and test
         self.assertEqual(self.ipv6.network,
@@ -1128,9 +1191,9 @@
                          ipaddr.IPv6Address('::ffff:ffff:ffff:ffff'))
 
         # V6 - check we're cached
-        self.assertTrue(self.ipv6._cache.has_key('network'))
-        self.assertTrue(self.ipv6._cache.has_key('broadcast'))
-        self.assertTrue(self.ipv6._cache.has_key('hostmask'))
+        self.assertTrue('network' in self.ipv6._cache)
+        self.assertTrue('broadcast' in self.ipv6._cache)
+        self.assertTrue('hostmask' in self.ipv6._cache)
 
     def testTeredo(self):
         # stolen from wikipedia
@@ -1158,6 +1221,12 @@
                          sixtofouraddr.sixtofour)
         self.assertFalse(bad_addr.sixtofour)
 
+    def testPickle(self):
+        for obj in (
+            ipaddr.IPv4Address('192.0.2.1'), ipaddr.IPv6Address('2001:db8::1'),
+            ipaddr.IPv4Network('192.0.2.1'), 
ipaddr.IPv6Network('2001:db8::1')):
+            self.assertEqual(obj, pickle.loads(pickle.dumps(obj)))
+
 
 if __name__ == '__main__':
     unittest.main()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ipaddr-2.1.11/setup.py new/ipaddr-2.2.0/setup.py
--- old/ipaddr-2.1.11/setup.py  2014-01-31 22:02:24.000000000 +0100
+++ new/ipaddr-2.2.0/setup.py   2017-09-15 20:46:08.000000000 +0200
@@ -18,18 +18,21 @@
 
 import ipaddr
 
-
 setup(name='ipaddr',
+      description="Google's IP address manipulation library",
+      long_description=open('README').read(),
       maintainer='Google',
       maintainer_email='[email protected]',
       version=ipaddr.__version__,
-      url='http://code.google.com/p/ipaddr-py/',
+      url='https://github.com/google/ipaddr-py',
       license='Apache License, Version 2.0',
       classifiers=[
-          'Development Status :: 5 - Production/Stable',
+          'Development Status :: 6 - Mature',
           'Intended Audience :: Developers',
           'License :: OSI Approved :: Apache Software License',
           'Operating System :: OS Independent',
+          'Programming Language :: Python',
+          'Programming Language :: Python :: 2',
           'Topic :: Internet',
           'Topic :: Software Development :: Libraries',
           'Topic :: System :: Networking'],


Reply via email to