Hello community, here is the log from the commit of package python-ipy for openSUSE:Factory checked in at 2018-11-26 10:29:50 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-ipy (Old) and /work/SRC/openSUSE:Factory/.python-ipy.new.19453 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-ipy" Mon Nov 26 10:29:50 2018 rev:8 rq:651338 version:0.83 Changes: -------- --- /work/SRC/openSUSE:Factory/python-ipy/python-ipy.changes 2013-12-09 16:59:44.000000000 +0100 +++ /work/SRC/openSUSE:Factory/.python-ipy.new.19453/python-ipy.changes 2018-11-26 10:30:27.601017171 +0100 @@ -1,0 +2,12 @@ +Thu Nov 22 14:26:39 UTC 2018 - [email protected] + +- Update to version 0.83 + * Add carrier grade NAT ranges + * Unbreak lots of packing systems by not having a letter in the release version + * Correct x.next() -> next(x) python3 compatability + * Add support for array slices + * Add __and__ and isdisjoint for IPSet + * Fix a bug in IPSet where contains may incorrectly return false +- Moved to singlespec and added explicit license + +------------------------------------------------------------------- Old: ---- IPy-0.81.tar.gz New: ---- IPy-0.83.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-ipy.spec ++++++ --- /var/tmp/diff_new_pack.SHcjF4/_old 2018-11-26 10:30:29.861014521 +0100 +++ /var/tmp/diff_new_pack.SHcjF4/_new 2018-11-26 10:30:29.861014521 +0100 @@ -1,7 +1,7 @@ # # spec file for package python-ipy # -# Copyright (c) 2013 SUSE LINUX Products GmbH, Nuernberg, Germany. +# Copyright (c) 2018 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 @@ -16,23 +16,21 @@ # -%define modname IPy - +%{?!python_module:%define python_module() python-%{**} python3-%{**}} Name: python-ipy -Version: 0.81 +Version: 0.83 Release: 0 +Summary: Class and tools for handling of IPv4 and IPv6 addresses and networks License: BSD-3-Clause -Summary: Class and Tools for Handling of IPv4 and IPv6 Addresses and Networks -Url: http://software.inl.fr/trac/wiki/IPy Group: Development/Languages/Python -Source: https://pypi.python.org/packages/source/I/IPy/IPy-%{version}.tar.gz -BuildRequires: python-devel -BuildRoot: %{_tmppath}/%{name}-%{version}-build -%if 0%{?suse_version} && 0%{?suse_version} <= 1110 -%{!?python_sitelib: %global python_sitelib %(python -c "from distutils.sysconfig import get_python_lib; print get_python_lib()")} -%else +Url: https://github.com/autocracy/python-ipy +Source: https://files.pythonhosted.org/packages/source/I/IPy/IPy-%{version}.tar.gz +BuildRequires: %{python_module setuptools} +BuildRequires: fdupes +BuildRequires: python-rpm-macros BuildArch: noarch -%endif + +%python_subpackages %description The IP class allows a comfortable parsing and handling for most @@ -42,17 +40,18 @@ so funky stuff like a netmask of 0xffffff0f can't be done here. %prep -%setup -q -n %{modname}-%{version} +%setup -q -n IPy-%{version} %build -python setup.py build +%python_build %install -python setup.py install --prefix=%{_prefix} --root=%{buildroot} - -%files -%defattr(-,root,root) -%doc AUTHORS COPYING ChangeLog README -%{python_sitelib} +%python_install +%python_expand %fdupes %{buildroot}%{$python_sitelib} +#install COPYING %{buildroot} + +%files %{python_files} +%{python_sitelib}/* +%license COPYING %changelog ++++++ IPy-0.81.tar.gz -> IPy-0.83.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/IPy-0.81/.gitignore new/IPy-0.83/.gitignore --- old/IPy-0.81/.gitignore 1970-01-01 01:00:00.000000000 +0100 +++ new/IPy-0.83/.gitignore 2015-04-05 02:48:02.000000000 +0200 @@ -0,0 +1,2 @@ +*.pyc +*.swp diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/IPy-0.81/AUTHORS new/IPy-0.83/AUTHORS --- old/IPy-0.81/AUTHORS 2013-03-27 01:53:18.000000000 +0100 +++ new/IPy-0.83/AUTHORS 2015-04-05 02:48:02.000000000 +0200 @@ -1,12 +1,12 @@ Authors ======= +Jeff Ferland <jeff AT storyinmemo.com> + > Current maintainer, versions 0.76 through latest +Victor Stinner <victor.stinner AT gmail.com> + > Maintainer, versions 0.5 through 0.75 Maximillian Dornseif <md AT hudora.de> > IPy author and maintainer until the version 0.42 -Victor Stinner <victor.stinner AT haypocalc.com> - > new maintainer since the version 0.5 -Jeff Ferland <jeff AT storyinmemo.com> - > New maintainer from version 0.76 Contributors ============ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/IPy-0.81/ChangeLog new/IPy-0.83/ChangeLog --- old/IPy-0.81/ChangeLog 2013-04-08 19:25:56.000000000 +0200 +++ new/IPy-0.83/ChangeLog 2015-04-05 02:48:02.000000000 +0200 @@ -1,4 +1,24 @@ +Version 0.83 (2015-04-04) +------------ + * Add carrier grade NAT ranges + * Unbreak lots of packing systems by not having a letter in the release version + +Version 0.82a (2014-10-07) +------------ + * Fix version numbers in files + * Correct x.next() -> next(x) python3 compatability + +Version 0.82 (2014-10-06) +------------ + + * Add support for array slices + * Add __and__ and isdisjoint for IPSet + * Fix a bug in IPSet where contains may incorrectly return false + * Added some fuzz testing + Version 0.81 (2013-04-08) +------------ + * Correct reverseName() for IPv6 addresses, so IP('::1').reverseName() returns correct. * Add network mask awareness to v46map() * Fix Python 3 errors in IPSet class diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/IPy-0.81/IPy.py new/IPy-0.83/IPy.py --- old/IPy-0.81/IPy.py 2013-04-01 23:42:25.000000000 +0200 +++ new/IPy-0.83/IPy.py 2015-04-05 02:48:02.000000000 +0200 @@ -6,7 +6,7 @@ https://github.com/haypo/python-ipy """ -__version__ = '0.81' +__version__ = '0.83' import bisect import collections @@ -20,6 +20,7 @@ '0': 'PUBLIC', # fall back '00000000': 'PRIVATE', # 0/8 '00001010': 'PRIVATE', # 10/8 + '0110010001': 'CARRIER_GRADE_NAT', #100.64/10 '01111111': 'PRIVATE', # 127.0/8 '1': 'PUBLIC', # fall back '1010100111111110': 'PRIVATE', # 169.254/16 @@ -610,6 +611,8 @@ IP('127.0.0.3') """ + if isinstance(key, slice): + return [self.ip + int(x) for x in xrange(*key.indices(len(self)))] if not isinstance(key, INT_TYPES): raise TypeError if key < 0: @@ -959,6 +962,8 @@ >>> print(str(ip[-1])) 127.0.0.3 """ + if isinstance(key, slice): + return [IP(IPint.__getitem__(self, x), ipversion=self._ipversion) for x in xrange(*key.indices(len(self)))] return IP(IPint.__getitem__(self, key), ipversion=self._ipversion) def __repr__(self): @@ -1012,12 +1017,7 @@ raise ValueError("%s cannot be converted to an IPv4 address." % repr(self)) -try: - IPSetBaseClass = collections.MutableSet -except AttributeError: - IPSetBaseClass = object - -class IPSet(IPSetBaseClass): +class IPSet(collections.MutableSet): def __init__(self, iterable=[]): # Make sure it's iterable, otherwise wrap if not isinstance(iterable, collections.Iterable): @@ -1038,13 +1038,11 @@ #Don't dig through more-specific ranges ip_mask = ip._prefixlen valid_masks = [x for x in valid_masks if x <= ip_mask] - for mask in valid_masks: + for mask in sorted(valid_masks): i = bisect.bisect(self.prefixtable[mask], ip) # Because of sorting order, a match can only occur in the prefix # that comes before the result of the search. - if i == 0: - return False - if ip in self.prefixtable[mask][i - 1]: + if i and ip in self.prefixtable[mask][i - 1]: return True def __iter__(self): @@ -1063,6 +1061,31 @@ new.discard(prefix) return new + def __and__(self, other): + left = iter(self.prefixes) + right = iter(other.prefixes) + result = [] + try: + l = next(left) + r = next(right) + while True: + # iterate over prefixes in order, keeping the smaller of the + # two if they overlap + if l in r: + result.append(l) + l = next(left) + continue + elif r in l: + result.append(r) + r = next(right) + continue + if l < r: + l = next(left) + else: + r = next(right) + except StopIteration: + return IPSet(result) + def __repr__(self): return '%s([' % self.__class__.__name__ + ', '.join(map(repr, self.prefixes)) + '])' @@ -1120,6 +1143,22 @@ self.optimize() + def isdisjoint(self, other): + left = iter(self.prefixes) + right = iter(other.prefixes) + try: + l = next(left) + r = next(right) + while True: + if l in r or r in l: + return False + if l < r: + l = next(left) + else: + r = next(right) + except StopIteration: + return True + def optimize(self): # The algorithm below *depends* on the sort order self.prefixes.sort() @@ -1597,7 +1636,7 @@ # Start cutting in half, recursively prefixes = [ IP('%s/%d' % (prefix[0], prefix._prefixlen + 1)), - IP('%s/%d' % (prefix[prefix.len() / 2], prefix._prefixlen + 1)), + IP('%s/%d' % (prefix[int(prefix.len() / 2)], prefix._prefixlen + 1)), ] if subprefix in prefixes[0]: return _remove_subprefix(prefixes[0], subprefix) + IPSet([prefixes[1]]) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/IPy-0.81/Makefile new/IPy-0.83/Makefile --- old/IPy-0.81/Makefile 1970-01-01 01:00:00.000000000 +0100 +++ new/IPy-0.83/Makefile 2015-04-05 02:48:02.000000000 +0200 @@ -0,0 +1,27 @@ +.PHONY: tests egg install clean + +PYTHON=python + +tests: + @echo "[ run unit tests in python 2 ]" + PYTHONPATH=$(PWD) $(PYTHON)2.6 test/test_IPy.py || exit $$? + @echo "[ run unit tests in python 3 ]" + PYTHONPATH=$(PWD) $(PYTHON)3.4 test/test_IPy.py || exit $$? + @echo + @echo "[ test README in python 2 ]" + $(PYTHON)2.6 test_doc.py || exit $$? + @echo "[ test README in python 3 ]" + $(PYTHON)3.4 test_doc.py || exit $$? + +egg: clean + $(PYTHON) setup.py sdist bdist_egg + +IPy.html: README + rst2html README $@ --stylesheet=rest.css + +install: + ./setup.py install + +clean: + rm -rf IPy.html *.pyc build dist IPy.egg-info + diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/IPy-0.81/PKG-INFO new/IPy-0.83/PKG-INFO --- old/IPy-0.81/PKG-INFO 2013-04-08 23:22:31.000000000 +0200 +++ new/IPy-0.83/PKG-INFO 1970-01-01 01:00:00.000000000 +0100 @@ -1,306 +0,0 @@ -Metadata-Version: 1.1 -Name: IPy -Version: 0.81 -Summary: Class and tools for handling of IPv4 and IPv6 addresses and networks -Home-page: https://github.com/haypo/python-ipy -Author: Jeff Ferland -Author-email: jeff AT storyinmemo.com -License: BSD License -Download-URL: https://github.com/haypo/python-ipy -Description: IPy - class and tools for handling of IPv4 and IPv6 addresses and networks. - - Website: https://github.com/haypo/python-ipy/ - - Presentation of the API - ======================= - - The IP class allows a comfortable parsing and handling for most - notations in use for IPv4 and IPv6 addresses and networks. It was - greatly inspired by RIPE's Perl module NET::IP's interface but - doesn't share the implementation. It doesn't share non-CIDR netmasks, - so funky stuff like a netmask of 0xffffff0f can't be done here. - - >>> from IPy import IP - >>> ip = IP('127.0.0.0/30') - >>> for x in ip: - ... print(x) - ... - 127.0.0.0 - 127.0.0.1 - 127.0.0.2 - 127.0.0.3 - >>> ip2 = IP('0x7f000000/30') - >>> ip == ip2 - 1 - >>> ip.reverseNames() - ['0.0.0.127.in-addr.arpa.', '1.0.0.127.in-addr.arpa.', '2.0.0.127.in-addr.arpa.', '3.0.0.127.in-addr.arpa.'] - >>> ip.reverseName() - '0-3.0.0.127.in-addr.arpa.' - >>> ip.iptype() - 'PRIVATE' - - - Supports most IP address formats - ================================ - - It can detect about a dozen different ways of expressing IP addresses - and networks, parse them and distinguish between IPv4 and IPv6 addresses: - - >>> IP('10.0.0.0/8').version() - 4 - >>> IP('::1').version() - 6 - - IPv4 addresses - -------------- - - >>> print(IP(0x7f000001)) - 127.0.0.1 - >>> print(IP('0x7f000001')) - 127.0.0.1 - >>> print(IP('127.0.0.1')) - 127.0.0.1 - >>> print(IP('10')) - 10.0.0.0 - - IPv6 addresses - -------------- - - >>> print(IP('1080:0:0:0:8:800:200C:417A')) - 1080::8:800:200c:417a - >>> print(IP('1080::8:800:200C:417A')) - 1080::8:800:200c:417a - >>> print(IP('::1')) - ::1 - >>> print(IP('::13.1.68.3')) - ::d01:4403 - - Network mask and prefixes - ------------------------- - - >>> print(IP('127.0.0.0/8')) - 127.0.0.0/8 - >>> print(IP('127.0.0.0/255.0.0.0')) - 127.0.0.0/8 - >>> print(IP('127.0.0.0-127.255.255.255')) - 127.0.0.0/8 - - - Derive network address - =========================== - - IPy can transform an IP address into a network address by applying the given - netmask: - >>> print(IP('127.0.0.1/255.0.0.0', make_net=True)) - 127.0.0.0/8 - - This can also be done for existing IP instances: - >>> print(IP('127.0.0.1').make_net('255.0.0.0')) - 127.0.0.0/8 - - - Convert address to string - ========================= - - Nearly all class methods which return a string have an optional - parameter 'wantprefixlen' which controls if the prefixlen or netmask - is printed. Per default the prefilen is always shown if the network - contains more than one address:: - - wantprefixlen == 0 / None don't return anything 1.2.3.0 - wantprefixlen == 1 /prefix 1.2.3.0/24 - wantprefixlen == 2 /netmask 1.2.3.0/255.255.255.0 - wantprefixlen == 3 -lastip 1.2.3.0-1.2.3.255 - - You can also change the defaults on an per-object basis by fiddling with - the class members: - - * NoPrefixForSingleIp - * WantPrefixLen - - Examples of string conversions: - - >>> IP('10.0.0.0/32').strNormal() - '10.0.0.0' - >>> IP('10.0.0.0/24').strNormal() - '10.0.0.0/24' - >>> IP('10.0.0.0/24').strNormal(0) - '10.0.0.0' - >>> IP('10.0.0.0/24').strNormal(1) - '10.0.0.0/24' - >>> IP('10.0.0.0/24').strNormal(2) - '10.0.0.0/255.255.255.0' - >>> IP('10.0.0.0/24').strNormal(3) - '10.0.0.0-10.0.0.255' - >>> ip = IP('10.0.0.0') - >>> print(ip) - 10.0.0.0 - >>> ip.NoPrefixForSingleIp = None - >>> print(ip) - 10.0.0.0/32 - >>> ip.WantPrefixLen = 3 - >>> print(ip) - 10.0.0.0-10.0.0.0 - - Work with multiple networks - =========================== - - Simple addition of neighboring netblocks that can be aggregated will yield - a parent network of both, but more complex range mapping and aggregation - requires is available with the IPSet class which will hold any number of - unique address ranges and will aggregate overlapping ranges. - - >>> from IPy import IP, IPSet - >>> IP('10.0.0.0/22') - IP('10.0.2.0/24') - IPSet([IP('10.0.0.0/23'), IP('10.0.3.0/24')]) - >>> IPSet([IP('10.0.0.0/23'), IP('10.0.3.0/24'), IP('10.0.2.0/24')]) - IPSet([IP('10.0.0.0/22')]) - >>> s = IPSet([IP('10.0.0.0/22')]) - >>> s.add(IP('192.168.1.0/29')) - >>> s - IPSet([IP('10.0.0.0/22'), IP('192.168.1.0/29')]) - >>> s.discard(IP('192.168.1.2')) - >>> s - IPSet([IP('10.0.0.0/22'), IP('192.168.1.0/31'), IP('192.168.1.3'), IP('192.168.1.4/30')]) - - Compatibility and links - ======================= - - IPy 0.81 works on Python version 2.5 - 3.3. - - This Python module is under BSD license: see COPYING file. - - Further Information might be available at: - https://github.com/haypo/python-ipy - - What's new - ========== - - Version 0.81 (2013-04-08) - * Correct reverseName() for IPv6 addresses, so IP('::1').reverseName() returns correct. - * Add network mask awareness to v46map() - * Fix Python 3 errors in IPSet class - * Make IPSet base class be object when MutableSet isn't available, fixing - errors in Python 2.5 - - Version 0.80 (2013-03-26) - ------------ - - * Drop support of Python older than 2.4 - * Python 3 does not need 2to3 conversion anymore (same code base) - * Fix adding of non-adjacent networks: - 192.168.0.0/24 + 192.168.255.0/24 made 192.168.0.0/23 - * Fix adding networks that don't create a valid subnet: - 192.168.1.0/24 + 192.168.2.0/24 made 192.168.1.0/23 - * Fix adding with an IPv6 address where .int() was < 32 bits made IPy believe it - was an IPv4 address: - ::ffff:0/112 + ::1:0:0/112 made 255.255.0.0/111 - * Add support of IPSets - * Add support for subtracting a network range - * Prevent IPv4 and IPv6 ranges from saying they contain each other - * Add a .v46map() method to convert mapped address ranges - such as IP('::ffff:192.168.1.1'); RFC 4291 - * Change sort order to more natural: - IPv4 before IPv6; less-specific prefixes first (/0 before /32) - - - Version 0.76 (2013-03-19) - ------------------------- - - * ip == other and ip != other doesn't fail with an exception anymore if other - is not a IP object - * Add IP.get_mac() method: get the 802.3 MAC address from IPv6 RFC 2464 - address. - * Fix IP('::/0')[0]: return an IPv6 instead of an IPv4 address - - Version 0.75 (2011-04-12) - ------------------------- - - * IP('::/0').netmask() gives IP('::') instead of IP('0.0.0.0') - - Version 0.74 (2011-02-16) - ------------------------- - - * Fix tests for Python 3.1 and 3.2 - * ip.__nonzero__() and (ipa in ipb) return a bool instead of 0 or 1 - * IP('0.0.0.0/0') + IP('0.0.0.0/0') raises an error, fix written by Arfrever - - Version 0.73 (2011-02-15) - ------------------------- - - * Support Python 3: setup.py runs 2to3 - * Update the ranges for IPv6 IPs - * Fix reverseName() and reverseNames() for IPv4 in IPv6 addresses - * Drop support of Python < 2.5 - - Version 0.72 (2010-11-23) - ------------------------- - - * Include examples and MANIFEST.in in source build (add them to - MANIFEST.in) - * Remove __rcsid__ constant from IPy module - - Version 0.71 (2010-10-01) - ------------------------- - - * Use xrange() instead of range() - * Use isinstance(x, int) instead of type(x) == types.IntType - * Prepare support of Python3 (use integer division: x // y) - * Fix IP(long) constructor: ensure that the address is not too large - * Constructor raise a TypeError if the type is not int, long, - str or unicode - * 223.0.0.0/8 is now public (belongs to APNIC) - - Version 0.70 (2009-10-29) - ------------------------- - - * New "major" version because it may break compatibility - * Fix __cmp__(): IP('0.0.0.0/0') and IP('0.0.0.0') are not equal - * Fix IP.net() of the network "::/0": "::" instead of "0.0.0.0". - IPy 0.63 should fix this bug, but it wasn't. - - Version 0.64 (2009-08-19) - ------------------------- - - * Create MANIFEST.in to fix setup.py bdist_rpm, fix by Robert Nickel - - Version 0.63 (2009-06-23) - ------------------------- - - * Fix formatting of "IPv4 in IPv6" network, eg. IP('::ffff:192.168.10.0/120'), - the netmask ("/120" in the example) was missing! - - Version 0.62 (2008-07-15) - ------------------------- - - * Fix reverse DNS of IPv6 address: use ".ip6.arpa." suffix instead of - deprecated ".ip6.int." suffix - - Version 0.61 (2008-06-12) - ------------------------- - - * Patch from Aras Vaichas allowing the [-1] operator - to work with an IP object of size 1. - - Version 0.60 (2008-05-16) - ------------------------- - - * strCompressed() formats '::ffff:a.b.c.d' correctly - * Use strCompressed() instead of strFullsize() to format IP addresses, - ouput is smarter with IPv6 address - * Remove check_addr_prefixlen because it generates invalid IP address -Keywords: ipv4 ipv6 netmask -Platform: UNKNOWN -Classifier: Development Status :: 5 - Production/Stable -Classifier: Intended Audience :: Developers -Classifier: Intended Audience :: System Administrators -Classifier: Environment :: Plugins -Classifier: Topic :: Software Development :: Libraries :: Python Modules -Classifier: Topic :: Communications -Classifier: Topic :: Internet -Classifier: Topic :: System :: Networking -Classifier: License :: OSI Approved :: BSD License -Classifier: Operating System :: OS Independent -Classifier: Natural Language :: English -Classifier: Programming Language :: Python -Classifier: Programming Language :: Python :: 3 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/IPy-0.81/README new/IPy-0.83/README --- old/IPy-0.81/README 2013-04-08 20:30:02.000000000 +0200 +++ new/IPy-0.83/README 2015-04-05 02:48:02.000000000 +0200 @@ -1,6 +1,6 @@ IPy - class and tools for handling of IPv4 and IPv6 addresses and networks. -Website: https://github.com/haypo/python-ipy/ +Website: https://github.com/autocracy/python-ipy/ Presentation of the API ======================= @@ -154,12 +154,39 @@ >>> s IPSet([IP('10.0.0.0/22'), IP('192.168.1.0/31'), IP('192.168.1.3'), IP('192.168.1.4/30')]) +IPSet supports the `set` method `isdisjoint`: + + >>> s.isdisjoint(IPSet([IP('192.168.0.0/16')])) + False + >>> s.isdisjoint(IPSet([IP('172.16.0.0/12')])) + True + +IPSet supports intersection: + + >>> s & IPSet([IP('10.0.0.0/8')]) + IPSet([IP('10.0.0.0/22')]) + Compatibility and links ======================= -IPy 0.81 works on Python version 2.5 - 3.3. +IPy 0.83 works on Python version 2.6 - 3.4. + +The IP module should work in Python 2.5 as long as the subtraction operation +is not used. IPSet requires features of the collecitons class which appear +in Python 2.6, though they can be backported. + +Eratta +====== + +When using IPv6 addresses, it is best to compare using IP().len() instead of +len(IP). Addresses with an integer value > 64 bits can break the 2nd method. +See http://stackoverflow.com/questions/15650878 for more info. + +Fuzz testing for IPSet will throw spurious errors when the IPSet module +combines two smaller prefixes into a larger prefix that matches the random +prefix tested against. This Python module is under BSD license: see COPYING file. Further Information might be available at: -https://github.com/haypo/python-ipy +https://github.com/autocracy/python-ipy diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/IPy-0.81/setup.py new/IPy-0.83/setup.py --- old/IPy-0.81/setup.py 2013-04-08 20:46:39.000000000 +0200 +++ new/IPy-0.83/setup.py 2015-04-05 02:48:02.000000000 +0200 @@ -24,7 +24,7 @@ import sys from distutils.core import setup -VERSION = '0.81' +VERSION = '0.83' options = {} @@ -54,7 +54,7 @@ 'Programming Language :: Python', 'Programming Language :: Python :: 3', ] -URL = "https://github.com/haypo/python-ipy" +URL = "https://github.com/autocracy/python-ipy" setup( name="IPy", diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/IPy-0.81/test/test_IPy.py new/IPy-0.83/test/test_IPy.py --- old/IPy-0.81/test/test_IPy.py 2013-03-27 01:53:18.000000000 +0100 +++ new/IPy-0.83/test/test_IPy.py 2015-04-05 02:48:02.000000000 +0200 @@ -16,8 +16,6 @@ import unittest import random -testloops = 250 - class parseAddress(unittest.TestCase): okValues = [('FEDC:BA98:7654:3210:FEDC:BA98:7654:3210', 338770000845734292534325025077361652240), ('FEDCBA9876543210FEDCBA9876543210', 338770000845734292534325025077361652240), @@ -202,21 +200,6 @@ self.assertRaises(ValueError, IPy.intToIp, 1, 7) self.assertRaises(ValueError, IPy.intToIp, 1, 8) -class ParseAndBack(unittest.TestCase): - def testRandomValuesv4(self): - for i in range(testloops): - question = random.randrange(0x7fffffff) + random.randrange(0x7fffffff) - self.assertEqual(IPy.parseAddress(IPy.intToIp(question, 4)), (question, 4), hex(question)) - - def testRandomValuesv6(self): - for i in range(testloops): - question = ((random.randrange(0x7fffffff) + random.randrange(0x7fffffff)) + - ((random.randrange(0x7fffffff) + random.randrange(0x7fffffff)) << 32) + - ((random.randrange(0x7fffffff) + random.randrange(0x7fffffff)) << 64) + - ((random.randrange(0x7fffffff) + random.randrange(0x7fffffff)) << 96)) - self.assertEqual(IPy.parseAddress(IPy.intToIp(question, 6)), (question, 6), hex(question)) - - class _countXBits(unittest.TestCase): def testCount1Bits(self): self.assertEqual(IPy._count1Bits(0), 0) @@ -463,6 +446,7 @@ self.assertEqual(ip[0], ip.net()) self.assertEqual(ip[-1], ip.broadcast()) self.assertTrue(ip[255]) + self.assertTrue(isinstance(ip[4::4], list)) self.assertRaises(IndexError, ip.__getitem__, 256) def testStr(self): @@ -844,10 +828,53 @@ self.t.discard(self.sixRange) self.assertEqual(self.t, self.c) + def testAnd(self): + ten24s = IPy.IPSet([ + IPy.IP('10.0.1.0/24'), + IPy.IP('10.0.3.0/24'), + IPy.IP('10.0.5.0/24'), + IPy.IP('10.0.7.0/24'), + ]) + + self.assertEqual(ten24s & IPy.IPSet([IPy.IP('10.0.1.10')]), + IPy.IPSet([IPy.IP('10.0.1.10')])) + + self.assertEqual(ten24s & IPy.IPSet([ + IPy.IP('10.0.0.99'), + IPy.IP('10.0.1.10'), + IPy.IP('10.0.3.40'), + IPy.IP('11.1.1.99'), + ]), IPy.IPSet([ + IPy.IP('10.0.1.10'), + IPy.IP('10.0.3.40'), + ])) + def testContains(self): self.assertTrue(IPy.IP('192.168.15.32/28') in self.t) self.assertFalse(IPy.IP('192.169.15.32/28') in self.t) + # test for a regression where __contains__ prematurely returns False + # after testing a prefix length where all IP instances are greater than + # the query IP. + ipset = IPy.IPSet([IPy.IP('10.0.0.0/8'), IPy.IP('128.0.0.0/1')]) + self.assertTrue(IPy.IP('10.0.0.0') in ipset) + + def testIsdisjoint(self): + self.assertTrue(IPy.IPSet([IPy.IP('0.0.0.0/1')]) + .isdisjoint(IPy.IPSet([IPy.IP('128.0.0.0/1')]))) + self.assertFalse(IPy.IPSet([IPy.IP('0.0.0.0/1')]) + .isdisjoint(IPy.IPSet([IPy.IP('0.0.0.0/2')]))) + self.assertFalse(IPy.IPSet([IPy.IP('0.0.0.0/2')]) + .isdisjoint(IPy.IPSet([IPy.IP('0.0.0.0/1')]))) + self.assertFalse(IPy.IPSet([IPy.IP('0.0.0.0/2')]) + .isdisjoint(IPy.IPSet([IPy.IP('0.1.2.3')]))) + self.assertFalse(IPy.IPSet([IPy.IP('0.1.2.3')]) + .isdisjoint(IPy.IPSet([IPy.IP('0.0.0.0/2')]))) + self.assertTrue(IPy.IPSet([IPy.IP('1.1.1.1'), IPy.IP('1.1.1.3')]) + .isdisjoint(IPy.IPSet([IPy.IP('1.1.1.2'), IPy.IP('1.1.1.4')]))) + self.assertFalse(IPy.IPSet([IPy.IP('1.1.1.1'), IPy.IP('1.1.1.3'), IPy.IP('1.1.2.0/24')]) + .isdisjoint(IPy.IPSet([IPy.IP('1.1.2.2'), IPy.IP('1.1.1.4')]))) + class RegressionTest(unittest.TestCase): def testNulNetmask(self): ip = timeout(IPy.IP, ["0.0.0.0/0.0.0.0"], timeout_duration=0.250, default=None) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/IPy-0.81/test/test_fuzz.py new/IPy-0.83/test/test_fuzz.py --- old/IPy-0.81/test/test_fuzz.py 1970-01-01 01:00:00.000000000 +0100 +++ new/IPy-0.83/test/test_fuzz.py 2015-04-05 02:48:02.000000000 +0200 @@ -0,0 +1,109 @@ +"""Fuzing for IPy.py""" + +# TODO: unify assert / FilIf usage + +import sys +import functools +import itertools +sys.path.append('.') +sys.path.append('..') + +import IPy +import unittest +import random + +if sys.version_info >= (3,): + xrange = range + +# on Python-2.7 and higher, we use load_tests to multiply out the test cases so that unittest +# represents each as an individual test case. +def iterate_27(n): + def wrap(func): + func.iterations = n + return func + return wrap + +def load_tests(loader, tests, pattern): + def expand(tests): + if isinstance(tests, unittest.TestCase): + method_name = tests._testMethodName + meth = getattr(tests, method_name) + if hasattr(meth, 'iterations'): + tests = unittest.TestSuite(type(tests)(method_name) for i in xrange(meth.iterations)) + else: + tests = unittest.TestSuite(expand(t) for t in tests) + return tests + return expand(tests) + +# On older Pythons, we run the requisite iterations directly, in a single test case. +def iterate_old(n): + def wrap(func): + @functools.wraps(func) + def replacement(*args): + for i in xrange(n): + func(*args) + return replacement + return wrap + +if sys.version_info >= (2,7): + iterate = iterate_27 +else: + iterate = iterate_old + +# utilities + +def random_ipv4_prefix(): + prefixlen = random.randrange(32) + int_ip = random.randrange(IPy.MAX_IPV4_ADDRESS) + int_ip &= 0xffffffff << (32-prefixlen) + return IPy.IP('.'.join(map(str, (int_ip >> 24, + (int_ip >> 16) & 0xff, + (int_ip >> 8) & 0xff, + int_ip & 0xff))) + + '/%d' % prefixlen) + +# tests + +class ParseAndBack(unittest.TestCase): + + @iterate(500) + def testRandomValuesv4(self): + question = random.randrange(0xffffffff) + self.assertEqual(IPy.parseAddress(IPy.intToIp(question, 4)), (question, 4), hex(question)) + + @iterate(500) + def testRandomValuesv6(self): + question = random.randrange(0xffffffffffffffffffffffffffffffff) + self.assertEqual(IPy.parseAddress(IPy.intToIp(question, 6)), (question, 6), hex(question)) + +class TestIPSet(unittest.TestCase): + + @iterate(1000) + def testRandomContains(self): + prefixes = [random_ipv4_prefix() for i in xrange(random.randrange(50))] + question = random_ipv4_prefix() + answer = any(question in pfx for pfx in prefixes) + ipset = IPy.IPSet(prefixes) + self.assertEqual(question in ipset, answer, + "%s in %s != %s (made from %s)" % (question, ipset, answer, prefixes)) + + + @iterate(1000) + def testRandomDisjoint(self): + prefixes1 = [random_ipv4_prefix() for i in xrange(random.randrange(50))] + prefixes2 = [random_ipv4_prefix() for i in xrange(random.randrange(50))] + # test disjointnes the stupid way + disjoint = True + for p1, p2 in itertools.product(prefixes1, prefixes2): + if p1 in p2 or p2 in p1: + disjoint = False + break + ipset1 = IPy.IPSet(prefixes1) + ipset2 = IPy.IPSet(prefixes2) + self.assertEqual(ipset1.isdisjoint(ipset2), disjoint, + "%s.isdisjoint(%s) != %s" % (ipset1, ipset2, disjoint)) + self.assertEqual(ipset2.isdisjoint(ipset1), disjoint, + "%s.isdisjoint(%s) != %s" % (ipset2, ipset1, disjoint)) + +if __name__ == "__main__": + unittest.main()
