[Python-modules-commits] r371 - in /packages/ipy: ./ branches/ branches/upstream/ branches/upstream/current/ branches/upstream/current/build/ branches/upstream/current/build/lib/ branches/upstream/current/example/ branches/upstream/current/test/ tags/

werner at users.alioth.debian.org werner at users.alioth.debian.org
Mon May 1 12:04:15 UTC 2006


Author: werner
Date: Mon May  1 12:03:34 2006
New Revision: 371

URL: http://svn.debian.org/wsvn/python-modules/?sc=1&rev=371
Log:
[svn-inject] Installing original source of ipy

Added:
    packages/ipy/
    packages/ipy/branches/
    packages/ipy/branches/upstream/
    packages/ipy/branches/upstream/current/
    packages/ipy/branches/upstream/current/CHANGES
    packages/ipy/branches/upstream/current/IPy.py
    packages/ipy/branches/upstream/current/MANIFEST.in
    packages/ipy/branches/upstream/current/README
    packages/ipy/branches/upstream/current/THANKS
    packages/ipy/branches/upstream/current/build/
    packages/ipy/branches/upstream/current/build/lib/
    packages/ipy/branches/upstream/current/build/lib/IPy.py
    packages/ipy/branches/upstream/current/example/
    packages/ipy/branches/upstream/current/example/confbuilder
    packages/ipy/branches/upstream/current/example/confbuilder.py
    packages/ipy/branches/upstream/current/setup.py
    packages/ipy/branches/upstream/current/test/
    packages/ipy/branches/upstream/current/test/test_IPy.py
    packages/ipy/tags/

Added: packages/ipy/branches/upstream/current/CHANGES
URL: http://svn.debian.org/wsvn/python-modules/packages/ipy/branches/upstream/current/CHANGES?rev=371&op=file
==============================================================================
--- packages/ipy/branches/upstream/current/CHANGES (added)
+++ packages/ipy/branches/upstream/current/CHANGES Mon May  1 12:03:34 2006
@@ -1,0 +1,5 @@
+IPy 0.42 works on Python 2.3 without warnings
+
+IPy 0.41 has Python < 2.2 compatible unit tests and a README file
+
+IPy 0.4 was the first public relase

Added: packages/ipy/branches/upstream/current/IPy.py
URL: http://svn.debian.org/wsvn/python-modules/packages/ipy/branches/upstream/current/IPy.py?rev=371&op=file
==============================================================================
--- packages/ipy/branches/upstream/current/IPy.py (added)
+++ packages/ipy/branches/upstream/current/IPy.py Mon May  1 12:03:34 2006
@@ -1,0 +1,1267 @@
+""" IPy - class and tools for handling of IPv4 and IPv6 Addresses and Networks.
+
+$HeadURL: http://svn.23.nu/svn/repos/IPy/trunk/IPy.py $
+
+$Id: IPy.py 671 2004-08-22 21:02:29Z md $
+
+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 bei RIPE's Perl module NET::IP's interface but
+doesn't share the Implementation. It doesn't share non-CIDR netmasks,
+so funky stuff lixe a netmask 0xffffff0f can't be done here.
+
+    >>> 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'
+
+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
+    >>> 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
+    >>> print IP('1080:0:0:0:8:800:200C:417A')
+    1080:0000:0000:0000:0008:0800:200c:417a
+    >>> print IP('1080::8:800:200C:417A')
+    1080:0000:0000:0000:0008:0800:200c:417a
+    >>> print IP('::1')
+    0000:0000:0000:0000:0000:0000:0000:0001
+    >>> print IP('::13.1.68.3')
+    0000:0000:0000:0000:0000:0000:0d01:4403
+    >>> 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
+
+Nearly all class methods which return a string have an optional
+parameter 'wantprefixlen' which controlles if the prefixlen or netmask
+is printed. Per default the prefilen is always shown if the net
+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 fiddeling with the class members
+
+NoPrefixForSingleIp
+WantPrefixLen
+
+    >>> 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
+                
+
+Further Information might be available at http://c0re.jp/c0de/IPy/
+
+Hacked 2001 by drt at un.bewaff.net
+
+TODO:
+      * better comparison (__cmp__ and friends)
+      * tests for __cmp__
+      * always write hex values lowercase
+      * interpret 2001:1234:5678:1234/64 as 2001:1234:5678:1234::/64
+      * move size in bits into class variables to get rid of some "if self._ipversion ..."
+      * support for base85 encoding
+      * support for output of IPv6 encoded IPv4 Addresses
+      * update address type tables      
+      * first-last notation should be allowed for IPv6
+      * add IPv6 docstring examples
+      * check better for negative parameters
+      * add addition / aggregation
+      * move reverse name stuff out of the classes and refactor it
+      * support for aggregation of more than two nets at once
+      * support for aggregation with "holes"
+      * support for finding common prefix
+      * '>>' and '<<' for prefix manipulation
+      * add our own exceptions instead ValueError all the time
+      * rename checkPrefix to checkPrefixOk
+      * add more documentation and doctests
+      * refactor
+"""
+
+__rcsid__ = '$Id: IPy.py 671 2004-08-22 21:02:29Z md $'
+__version__ = '0.42'
+
+import types
+
+# Definition of the Ranges for IPv4 IPs
+# this should include www.iana.org/assignments/ipv4-address-space
+# and www.iana.org/assignments/multicast-addresses
+IPv4ranges = {
+    '0'	   	        : 'PUBLIC',   # fall back
+    '00000000'		: 'PRIVATE',  # 0/8
+    '00001010'		: 'PRIVATE',  # 10/8
+    '01111111'		: 'PRIVATE',  # 127.0/8
+    '1'		        : 'PUBLIC',   # fall back
+    '101011000001'      : 'PRIVATE',  # 172.16/12
+    '1100000010101000'	: 'PRIVATE',  # 192.168/16
+    '11011111'		: 'RESERVED', # 223/8
+    '111'	        : 'RESERVED'  # 224/3
+    }
+
+# Definition of the Ranges for IPv6 IPs
+# see also www.iana.org/assignments/ipv6-address-space,
+# www.iana.org/assignments/ipv6-tla-assignments,
+# www.iana.org/assignments/ipv6-multicast-addresses,
+# www.iana.org/assignments/ipv6-anycast-addresses
+IPv6ranges = {
+    '00000000'              : 'RESERVED',       # ::/8
+    '00000001'              : 'UNASSIGNED',     # 100::/8
+    '0000001'               : 'NSAP',           # 200::/7
+    '0000010'               : 'IPX',            # 400::/7
+    '0000011'               : 'UNASSIGNED',     # 600::/7   
+    '00001'                 : 'UNASSIGNED',     # 800::/5
+    '0001'                  : 'UNASSIGNED',     # 1000::/4
+    '0010000000000000'      : 'RESERVED',       # 2000::/16 Reserved
+    '0010000000000001'      : 'ASSIGNABLE',     # 2001::/16 Sub-TLA Assignments [RFC2450]
+    '00100000000000010000000': 'ASSIGNABLE IANA',  # 2001:0000::/29 - 2001:01F8::/29 IANA
+    '00100000000000010000001': 'ASSIGNABLE APNIC', # 2001:0200::/29 - 2001:03F8::/29 APNIC
+    '00100000000000010000010': 'ASSIGNABLE ARIN',  # 2001:0400::/29 - 2001:05F8::/29 ARIN
+    '00100000000000010000011': 'ASSIGNABLE RIPE',  # 2001:0600::/29 - 2001:07F8::/29 RIPE NCC
+    '0010000000000010'      : '6TO4',           # 2002::/16 "6to4" [RFC3056]
+    '0011111111111110'      : '6BONE',          # 3FFE::/16 6bone Testing [RFC2471]
+    '0011111111111111'      : 'RESERVED',       # 3FFF::/16 Reserved
+    '010'                   : 'GLOBAL-UNICAST', # 4000::/3              
+    '011'                   : 'UNASSIGNED',     # 6000::/3
+    '100'                   : 'GEO-UNICAST',    # 8000::/3
+    '101'                   : 'UNASSIGNED',     # A000::/3
+    '110'                   : 'UNASSIGNED',     # C000::/3
+    '1110'                  : 'UNASSIGNED',     # E000::/4
+    '11110'                 : 'UNASSIGNED',     # F000::/5
+    '111110'                : 'UNASSIGNED',     # F800::/6
+    '1111110'               : 'UNASSIGNED',     # FC00::/7
+    '111111100'             : 'UNASSIGNED',     # FE00::/9
+    '1111111010'            : 'LINKLOCAL',      # FE80::/10
+    '1111111011'            : 'SITELOCAL',      # FEC0::/10
+    '11111111'              : 'MULTICAST',      # FF00::/8
+    '0' * 96                : 'IPV4COMP',       # ::/96
+    '0' * 80 + '1' * 16     : 'IPV4MAP',        # ::FFFF:0:0/96
+    '0' * 128               : 'UNSPECIFIED',    # ::/128
+    '0' * 127 + '1'         : 'LOOPBACK'        # ::1/128
+    }
+
+
+class IPint:
+    """Handling of IP addresses returning integers.
+
+    Use class IP instead because some features are not implemented for
+    IPint."""
+    
+    def __init__(self, data, ipversion = 0):
+        """Create an instance of an IP object.
+        
+        Data can be a network specification or a single IP. IP
+        Addresses can be specified in all forms understood by
+        parseAddress.() the size of a network can be specified as
+
+        /prefixlen        a.b.c.0/24               2001:658:22a:cafe::/64
+        -lastIP           a.b.c.0-a.b.c.255        2001:658:22a:cafe::-2001:658:22a:cafe:ffff:ffff:ffff:ffff
+        /decimal netmask  a.b.c.d/255.255.255.0    not supported for IPv6
+
+        If no size specification is given a size of 1 address (/32 for
+        IPv4 and /128 for IPv6) is assumed.
+
+        >>> 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
+
+        See module documentation for more examples.
+        """
+
+        self.NoPrefixForSingleIp = 1  # Print no Prefixlen for /32 and /128
+        self.WantPrefixLen = None     # Do we want prefix printed by default? see _printPrefix()
+        
+        netbits = 0
+        prefixlen = -1
+        
+        # handling of non string values in constructor
+        if type(data) == types.IntType or type(data) == types.LongType:
+            self.ip = long(data)
+            if ipversion == 0:
+                if self.ip < 0x100000000L:
+                    ipversion = 4
+                else:
+                    ipversion = 6
+            if ipversion == 4:
+                prefixlen = 32
+            elif ipversion == 6:
+                prefixlen = 128
+            else:
+                raise ValueError, "only IPv4 and IPv6 supported"
+            self._ipversion = ipversion
+            self._prefixlen = prefixlen
+        # handle IP instance as an parameter
+        elif isinstance(data, IPint):
+            self._ipversion = data._ipversion
+            self._prefixlen = data._prefixlen
+            self.ip = data.ip
+        else:
+            # TODO: refactor me!
+            # splitting of a string into IP and prefixlen et. al.
+            x = data.split('-')
+            if len(x) == 2:
+                # a.b.c.0-a.b.c.255 specification ?
+                (ip, last) = x
+                (self.ip, parsedVersion) = parseAddress(ip)
+                if parsedVersion != 4:
+                    raise ValueError, "first-last notation only allowed for IPv4"
+                (last, lastversion) = parseAddress(last)
+                if lastversion != 4:
+                    raise ValueError, "last address should be IPv4, too"
+                if last < self.ip:
+                    raise ValueError, "last address should be larger than first"
+                size = last - self.ip
+                netbits = _count1Bits(size)
+            elif len(x) == 1:    
+                x = data.split('/')
+                # if no prefix is given use defaults
+                if len(x) == 1:
+                    ip = x[0]
+                    prefixlen = -1
+                elif len(x) > 2:
+                    raise ValueError, "only one '/' allowed in IP Address"
+                else:
+                    (ip, prefixlen) = x
+                    if prefixlen.find('.') != -1:
+                        # check if the user might have used a netmask like
+                        # a.b.c.d/255.255.255.0
+                        (netmask, vers) = parseAddress(prefixlen)
+                        if vers != 4:
+                            raise ValueError, "netmask must be IPv4"
+                        prefixlen = _netmaskToPrefixlen(netmask)                         
+            elif len(x) > 2:
+                raise ValueError, "only one '-' allowed in IP Address"
+            else:
+                raise ValueError, "can't parse"
+
+            (self.ip, parsedVersion) = parseAddress(ip)
+            if ipversion == 0:
+                ipversion = parsedVersion
+            if prefixlen == -1:
+                if ipversion == 4:
+                    prefixlen = 32 - netbits
+                elif ipversion == 6:
+                    prefixlen = 128 - netbits
+                else:
+                    raise ValueError, "only IPv4 and IPv6 supported"
+            self._ipversion = ipversion
+            self._prefixlen = int(prefixlen)
+
+            if not _checkNetaddrWorksWithPrefixlen(self.ip, self._prefixlen, self._ipversion):
+                raise ValueError, "%s goes not well with prefixlen %d" % (hex(self.ip), self._prefixlen) 
+                
+
+    def int(self):
+        """Return the first / base / network addess as an (long) integer.
+
+        The same as IP[0].
+
+        >>> hex(IP('10.0.0.0/8').int())
+        '0xA000000L'
+        """
+        return self.ip
+
+    def version(self):
+        """Return the IP version of this Object.
+
+        >>> IP('10.0.0.0/8').version()
+        4
+        >>> IP('::1').version()
+        6
+        """
+        return self._ipversion
+
+    def prefixlen(self):
+        """Returns Network Prefixlen.
+
+        >>> IP('10.0.0.0/8').prefixlen()
+        8
+        """
+        return self._prefixlen
+
+    def net(self):
+        """Return the base (first) address of a network as an (long) integer."""
+
+        return self.int()
+
+    def broadcast(self):
+        """Return the broadcast (last) address of a network as an (long) integer.
+
+        The same as IP[-1]."""
+        return self.int() + self.len() - 1
+
+    def _printPrefix(self, want):
+        """Prints Prefixlen/Netmask.
+
+        Not really. In fact it is our universal Netmask/Prefixlen printer.
+        This is considered an internel function.
+
+        want == 0 / None        don't return anything    1.2.3.0
+        want == 1               /prefix                  1.2.3.0/24
+        want == 2               /netmask                 1.2.3.0/255.255.255.0
+        want == 3               -lastip                  1.2.3.0-1.2.3.255
+        """
+
+        if (self._ipversion == 4 and self._prefixlen == 32) or \
+           (self._ipversion == 6 and self._prefixlen == 128): 
+            if self.NoPrefixForSingleIp:
+                want = 0
+        if want == None:
+            want = self.WantPrefixLen
+            if want == None:
+                want = 1
+        if want:
+            if want == 2:
+                # this should work wit IP and IPint
+                netmask = self.netmask()
+                if type(netmask) != types.IntType and type(netmask) != types.LongType:
+                    netmask = netmask.int()
+                return "/%s" % (intToIp(netmask, self._ipversion))
+            elif want == 3:
+                return "-%s" % (intToIp(self.ip + self.len() - 1, self._ipversion))
+            else:
+                # default
+                return "/%d" % (self._prefixlen)
+        else:
+            return ''
+
+        # We have different Favours to convert to:
+        # strFullsize   127.0.0.1    2001:0658:022a:cafe:0200:c0ff:fe8d:08fa
+        # strNormal     127.0.0.1    2001:658:22a:cafe:200:c0ff:fe8d:08fa
+        # strCompressed 127.0.0.1    2001:658:22a:cafe::1
+        # strHex        0x7F000001L  0x20010658022ACAFE0200C0FFFE8D08FA
+        # strDec        2130706433   42540616829182469433547974687817795834
+
+    def strBin(self, wantprefixlen = None): 
+        """Return a string representation as a binary value.
+
+        >>> print IP('127.0.0.1').strBin()
+        01111111000000000000000000000001
+        """
+
+
+        if self._ipversion == 4:
+            bits = 32 
+        elif self._ipversion == 6:
+            bits = 128
+        else:
+            raise ValueError, "only IPv4 and IPv6 supported"
+
+        if self.WantPrefixLen == None and wantprefixlen == None:
+            wantprefixlen = 0
+        ret = _intToBin(self.ip)
+        return  '0' * (bits - len(ret)) + ret + self._printPrefix(wantprefixlen)
+
+    def strCompressed(self, wantprefixlen = None):
+        """Return a string representation in compressed format using '::' Notation.
+
+        >>> print IP('127.0.0.1').strCompressed()
+        127.0.0.1
+        >>> print IP('2001:0658:022a:cafe:0200::1').strCompressed()
+        2001:658:22a:cafe:200::1
+        """
+                
+        if self.WantPrefixLen == None and wantprefixlen == None:
+            wantprefixlen = 1
+            
+        if self._ipversion == 4:
+            return self.strFullsize(wantprefixlen)
+        else:
+            # find the longest sequence of '0'
+            hextets = [int(x, 16) for x in self.strFullsize(0).split(':')]
+            # every element of followingzeros will contain the number of zeros
+            # following the corrospondending element of hextetes
+            followingzeros = [0] * 8
+            for i in range(len(hextets)):
+                followingzeros[i] = _countFollowingZeros(hextets[i:])
+            # compressionpos is the position where we can start removing zeros
+            compressionpos = followingzeros.index(max(followingzeros))
+            if max(followingzeros) > 1:
+                # genererate string with the longest number of zeros cut out
+                # now we need hextets as strings
+                hextets = [x for x in self.strNormal(0).split(':')]
+                while compressionpos < len(hextets) and hextets[compressionpos] == '0':
+                    del(hextets[compressionpos])
+                hextets.insert(compressionpos, '')
+                if compressionpos + 1 >= len(hextets):
+                    hextets.append('')
+                if compressionpos == 0:
+                    hextets = [''] + hextets
+                return ':'.join(hextets) + self._printPrefix(wantprefixlen)
+            else:
+                return self.strNormal() + self._printPrefix(wantprefixlen)
+
+    def strNormal(self, wantprefixlen = None):
+        """Return a string representation in the usual format.
+
+        >>> print IP('127.0.0.1').strNormal()
+        127.0.0.1
+        >>> print IP('2001:0658:022a:cafe:0200::1').strNormal()
+        2001:658:22a:cafe:200:0:0:1
+        """
+
+        if self.WantPrefixLen == None and wantprefixlen == None:
+            wantprefixlen = 1
+        
+        if self._ipversion == 4:
+            ret = self.strFullsize(0) 
+        elif self._ipversion == 6:
+            ret = ':'.join([hex(x)[2:] for x in [int(x, 16) for x in self.strFullsize(0).split(':')]])
+        else:
+            raise ValueError, "only IPv4 and IPv6 supported"
+
+            
+        
+        return ret + self._printPrefix(wantprefixlen)
+
+    def strFullsize(self, wantprefixlen = None):
+        """Return a string representation in the non mangled format.
+
+        >>> print IP('127.0.0.1').strFullsize()
+        127.0.0.1
+        >>> print IP('2001:0658:022a:cafe:0200::1').strFullsize()
+        2001:0658:022a:cafe:0200:0000:0000:0001
+        """
+
+        if self.WantPrefixLen == None and wantprefixlen == None:
+            wantprefixlen = 1
+            
+        return intToIp(self.ip, self._ipversion).lower() + self._printPrefix(wantprefixlen)
+
+    def strHex(self, wantprefixlen = None):
+        """Return a string representation in hex format.
+
+        >>> print IP('127.0.0.1').strHex()
+        0x7F000001
+        >>> print IP('2001:0658:022a:cafe:0200::1').strHex()
+        0x20010658022ACAFE0200000000000001
+        """
+
+        if self.WantPrefixLen == None and wantprefixlen == None:
+            wantprefixlen = 0
+
+        x = hex(self.ip)
+        if x[-1] == 'L':
+            x = x[:-1]
+        return x + self._printPrefix(wantprefixlen)
+
+    def strDec(self, wantprefixlen = None):
+        """Return a string representation in decimal format.
+
+        >>> print IP('127.0.0.1').strDec()
+        2130706433
+        >>> print IP('2001:0658:022a:cafe:0200::1').strDec()
+        42540616829182469433547762482097946625
+        """
+
+        if self.WantPrefixLen == None and wantprefixlen == None:
+            wantprefixlen = 0
+
+        x =  str(self.ip)
+        if x[-1] == 'L':
+            x = x[:-1]
+        return x + self._printPrefix(wantprefixlen)
+
+    def iptype(self):
+        """Return a description of the IP type ('PRIVATE', 'RESERVERD', etc).
+
+        >>> print IP('127.0.0.1').iptype()
+        PRIVATE
+        >>> print IP('192.168.1.1').iptype()
+        PRIVATE
+        >>> print IP('195.185.1.2').iptype()
+        PUBLIC
+        >>> print IP('::1').iptype()
+        LOOPBACK
+        >>> print IP('2001:0658:022a:cafe:0200::1').iptype()
+        ASSIGNABLE RIPE
+
+        The type information for IPv6 is out of sync with reality.
+        """
+
+        # this could be greatly improved
+
+        if self._ipversion == 4:
+            iprange = IPv4ranges 
+        elif self._ipversion == 6:
+            iprange = IPv6ranges 
+        else:
+            raise ValueError, "only IPv4 and IPv6 supported"
+
+        bits = self.strBin()
+        for i in range(len(bits), 0, -1):
+            if iprange.has_key(bits[:i]):
+                return iprange[bits[:i]]
+        return "unknown"
+
+
+    def netmask(self):
+        """Return netmask as an integer.
+
+        >>> print hex(IP('195.185.0.0/16').netmask().int())
+        0xFFFF0000L
+        """
+
+        # TODO: unify with prefixlenToNetmask?
+        if self._ipversion == 4:
+            locallen = 32 - self._prefixlen
+        elif self._ipversion == 6:
+            locallen = 128 - self._prefixlen
+        else:
+            raise ValueError, "only IPv4 and IPv6 supported"
+
+        return ((2L ** self._prefixlen) - 1) << locallen
+
+
+    def strNetmask(self):
+        """Return netmask as an string. Mostly useful for IPv6.
+
+        >>> print IP('195.185.0.0/16').strNetmask()
+        255.255.0.0
+        >>> print IP('2001:0658:022a:cafe::0/64').strNetmask()
+        /64
+        """
+
+        # TODO: unify with prefixlenToNetmask?
+        if self._ipversion == 4:
+            locallen = 32 - self._prefixlen
+            return intToIp(((2L ** self._prefixlen) - 1) << locallen, 4)
+        elif self._ipversion == 6:
+            locallen = 128 - self._prefixlen
+            return "/%d" % self._prefixlen
+        else:
+            raise ValueError, "only IPv4 and IPv6 supported"
+
+    def len(self):
+        """Return the length of an subnet.
+
+        >>> print IP('195.185.1.0/28').len()
+        16
+        >>> print IP('195.185.1.0/24').len()
+        256
+        """
+
+        if self._ipversion == 4:
+            locallen = 32 - self._prefixlen
+        elif self._ipversion == 6:
+            locallen = 128 - self._prefixlen
+        else:
+            raise ValueError, "only IPv4 and IPv6 supported"
+
+        return 2L ** locallen 
+
+
+    def __len__(self):
+        """Return the length of an subnet.
+
+        Called to implement the built-in function len().
+        It breaks with IPv6 Networks. Anybody knows how to fix this."""
+
+        # Python < 2.2 has this silly restriction which breaks IPv6
+        # how about Python >= 2.2 ... ouch - it presists!
+    
+        return int(self.len())
+
+
+    def __getitem__(self, key):
+        """Called to implement evaluation of self[key].
+        
+        >>> ip=IP('127.0.0.0/30')
+        >>> for x in ip:
+        ...  print hex(x.int())
+        ...
+        0x7F000000L
+        0x7F000001L
+        0x7F000002L
+        0x7F000003L
+        >>> hex(ip[2].int())
+        '0x7F000002L'
+        >>> hex(ip[-1].int())
+        '0x7F000003L'
+        """
+
+        if type(key) != types.IntType and type(key) != types.LongType:
+            raise TypeError
+        if abs(key) >= self.len():
+            raise IndexError
+        if key < 0:
+            key = self.len() - abs(key)
+
+        return self.ip + long(key)
+
+    
+
+    def __contains__(self, item):
+        """Called to implement membership test operators.
+
+        Should return true if item is in self, false otherwise. Item
+        can be other IP-objects, strings or ints.
+
+        >>> print IP('195.185.1.1').strHex()
+        0xC3B90101
+        >>> 0xC3B90101L in IP('195.185.1.0/24')
+        1
+        >>> '127.0.0.1' in IP('127.0.0.0/24')
+        1
+        >>> IP('127.0.0.0/24') in IP('127.0.0.0/25')
+        0
+        """
+
+        item = IP(item)
+        if item.ip >= self.ip and item.ip < self.ip + self.len() - item.len() + 1:
+            return 1
+        else:
+            return 0
+
+
+    def overlaps(self, item):
+        """Check if two IP address ranges overlap.
+
+        Returns 0 if the two ranged don't overlap, 1 if the given
+        range overlaps at the end and -1 if it does at the beginning.
+
+        >>> IP('192.168.0.0/23').overlaps('192.168.1.0/24')
+        1
+        >>> IP('192.168.0.0/23').overlaps('192.168.1.255')
+        1
+        >>> IP('192.168.0.0/23').overlaps('192.168.2.0')
+        0
+        >>> IP('192.168.1.0/24').overlaps('192.168.0.0/23')
+        -1
+        """
+
+        item = IP(item)
+        if item.ip >= self.ip and item.ip < self.ip + self.len():
+            return 1
+        elif self.ip >= item.ip and self.ip < item.ip + item.len():
+            return -1
+        else:
+            return 0
+
+    
+    def __str__(self):
+        """Dispatch to the prefered String Representation.
+
+        Used to implement str(IP)."""
+
+        return self.strFullsize()
+
+
+    def __repr__(self):
+        """Print a representation of the Object.
+
+        Used to implement repr(IP). Returns a string which evaluates
+        to an identical Object (without the wnatprefixlen stuff - see
+        module docstring.
+
+        >>> print repr(IP('10.0.0.0/24'))
+        IP('10.0.0.0/24')
+        """
+
+        return("IPint('%s')" % (self.strCompressed(1))) 
+
+
+    def __cmp__(self, other):
+        """Called by comparison operations.
+
+        Should return a negative integer if self < other, zero if self
+        == other, a positive integer if self > other.
+
+        Networks with different prefixlen are considered non-equal.
+        Networks with the same prefixlen and differing addresses are
+        considered non equal but are compared by thair base address
+        integer value to aid sorting of IP objects.
+
+        The Version of Objects is not put into consideration.
+
+        >>> IP('10.0.0.0/24') > IP('10.0.0.0')
+        1
+        >>> IP('10.0.0.0/24') < IP('10.0.0.0')
+        0
+        >>> IP('10.0.0.0/24') < IP('12.0.0.0/24')
+        1
+        >>> IP('10.0.0.0/24') > IP('12.0.0.0/24')
+        0
+
+        """
+
+        # Im not really sure if this is "the right thing to do"
+        if self._prefixlen < other.prefixlen():
+            return (other.prefixlen() - self._prefixlen) 
+        elif self._prefixlen > other.prefixlen():
+
+            # Fixed bySamuel Krempp <krempp at crans.ens-cachan.fr>:
+            
+            # The bug is quite obvious really (as 99% bugs are once
+            # spotted, isn't it ? ;-) Because of precedence of
+            # multiplication by -1 over the substraction, prefixlen
+            # differences were causing the __cmp__ function to always
+            # return positive numbers, thus the function was failing
+            # the basic assumptions for a __cmp__ function.
+
+            # Namely we could have (a > b AND b > a), when the
+            # prefixlen of a and b are different.  (eg let
+            # a=IP("1.0.0.0/24"); b=IP("2.0.0.0/16");) thus, anything
+            # could happen when launching a sort algorithm..
+            # everything's in order with the trivial, attached patch.
+                                             
+            return (self._prefixlen - other.prefixlen()) * -1
+        else:
+            if self.ip < other.ip:
+                return -1 
+            elif self.ip > other.ip:
+                return 1
+            else:
+                return 0
+        
+     
+    def __hash__(self):
+        """Called for the key object for dictionary operations, and by
+        the built-in function hash()  Should return a 32-bit integer
+        usable as a hash value for dictionary operations. The only
+        required property is that objects which compare equal have the
+        same hash value
+
+        >>> hex(IP('10.0.0.0/24').__hash__())
+        '0xf5ffffe7'
+        """
+
+        thehash = int(-1)
+        ip = self.ip
+        while ip > 0:
+            thehash = thehash ^ (ip & 0x7fffffff)
+            ip = ip >> 32
+        thehash = thehash ^ self._prefixlen
+        return int(thehash)
+
+
+class IP(IPint):
+    """Class for handling IP Addresses and Networks."""
+
+    def net(self):
+        """Return the base (first) address of a network as an IP object.
+
+        The same as IP[0].
+
+        >>> IP('10.0.0.0/8').net()
+        IP('10.0.0.0')
+        """
+        return IP(IPint.net(self))
+
+    def broadcast(self):
+        """Return the broadcast (last) address of a network as an IP object.
+
+        The same as IP[-1].
+
+        >>> IP('10.0.0.0/8').broadcast()
+        IP('10.255.255.255')
+        """
+        return IP(IPint.broadcast(self))
+
+    def netmask(self):
+        """Return netmask as an IP object.
+
+        >>> IP('10.0.0.0/8').netmask()
+        IP('255.0.0.0')
+         """
+        return IP(IPint.netmask(self))
+
+
+    def reverseNames(self):
+        """Return a list with values forming the reverse lookup.
+
+        >>> IP('213.221.113.87/32').reverseNames()
+        ['87.113.221.213.in-addr.arpa.']
+        >>> IP('213.221.112.224/30').reverseNames()
+        ['224.112.221.213.in-addr.arpa.', '225.112.221.213.in-addr.arpa.', '226.112.221.213.in-addr.arpa.', '227.112.221.213.in-addr.arpa.']
+        >>> IP('127.0.0.0/24').reverseNames()
+        ['0.0.127.in-addr.arpa.']
+        >>> IP('127.0.0.0/23').reverseNames()
+        ['0.0.127.in-addr.arpa.', '1.0.127.in-addr.arpa.']
+        >>> IP('127.0.0.0/16').reverseNames()
+        ['0.127.in-addr.arpa.']
+        >>> IP('127.0.0.0/15').reverseNames()
+        ['0.127.in-addr.arpa.', '1.127.in-addr.arpa.']
+        >>> IP('128.0.0.0/8').reverseNames()
+        ['128.in-addr.arpa.']
+        >>> IP('128.0.0.0/7').reverseNames()
+        ['128.in-addr.arpa.', '129.in-addr.arpa.']
+        
+        """
+
+        if self._ipversion == 4:
+            ret =[]
+            # TODO: Refactor. Add support for IPint objects
+            if self.len() < 2**8:
+                for x in self:
+                    ret.append(x.reverseName())
+            elif self.len() < 2**16L:
+                for i in range(0, self.len(), 2**8):
+                    ret.append(self[i].reverseName()[2:])
+            elif self.len() < 2**24L:
+                for i in range(0, self.len(), 2**16):
+                    ret.append(self[i].reverseName()[4:])
+            else:
+                for i in range(0, self.len(), 2**24):
+                    ret.append(self[i].reverseName()[6:])
+            return ret
+        elif self._ipversion == 6:
+            s = hex(self.ip)[2:].lower()
+            if s[-1] == 'l':
+                s = s[:-1]
+            if self._prefixlen % 4 != 0:
+                raise NotImplementedError, "can't create IPv6 reverse names at sub nibble level"
+            s = list(s)
+            s.reverse()
+            s = '.'.join(s)
+            first_nibble_index = int(32 - (self._prefixlen / 4)) * 2
+            return ["%s.ip6.int." % s[first_nibble_index:]]
+        else:
+            raise ValueError, "only IPv4 and IPv6 supported"
+        
+        
+
+    def reverseName(self):
+        """Return the value for reverse lookup/PTR records as RfC 2317 look alike.
+
+        RfC 2317 is an ugly hack which only works for sub-/24 e.g. not
+        for /23. Do not use it. Better set up a Zone for every
+        address. See reverseName for a way to arcive that.
+
+        >>> print IP('195.185.1.1').reverseName()
+        1.1.185.195.in-addr.arpa.
+        >>> print IP('195.185.1.0/28').reverseName()
+        0-15.1.185.195.in-addr.arpa.
+        """
+
+        if self._ipversion == 4:
+            s = self.strFullsize(0)
+            s = s.split('.')
+            s.reverse()
+            first_byte_index = int(4 - (self._prefixlen / 8)) 
+            if self._prefixlen % 8 != 0:
+                nibblepart = "%s-%s" % (s[3-(self._prefixlen / 8)], intToIp(self.ip + self.len() - 1, 4).split('.')[-1])
+                if nibblepart[-1] == 'l':
+                    nibblepart = nibblepart[:-1]
+                nibblepart += '.'
+            else:
+                nibblepart = ""
+
+            s = '.'.join(s[first_byte_index:])
+            return "%s%s.in-addr.arpa." % (nibblepart, s)
+
+        elif self._ipversion == 6:
+            s = hex(self.ip)[2:].lower()
+            if s[-1] == 'l':
+                s = s[:-1]
+            if self._prefixlen % 4 != 0:
+                nibblepart = "%s-%s" % (s[self._prefixlen:], hex(self.ip + self.len() - 1)[2:].lower())
+                if nibblepart[-1] == 'l':
+                    nibblepart = nibblepart[:-1]
+                nibblepart += '.'
+            else:
+                nibblepart = ""
+            s = list(s)
+            s.reverse()
+            s = '.'.join(s)
+            first_nibble_index = int(32 - (self._prefixlen / 4)) * 2
+            return "%s%s.ip6.int." % (nibblepart, s[first_nibble_index:])
+        else:
+            raise ValueError, "only IPv4 and IPv6 supported"
+
+    def __getitem__(self, key):
+        """Called to implement evaluation of self[key].
+        
+        >>> ip=IP('127.0.0.0/30')
+        >>> for x in ip:
+        ...  print str(x)
+        ...
+        127.0.0.0
+        127.0.0.1
+        127.0.0.2
+        127.0.0.3
+        >>> print str(ip[2])
+        127.0.0.2
+        >>> print str(ip[-1])
+        127.0.0.3
+        """
+        return IP(IPint.__getitem__(self, key))
+
+    def __repr__(self):
+        """Print a representation of the Object.
+
+        >>> IP('10.0.0.0/8')
+        IP('10.0.0.0/8')
+        """
+
+        return("IP('%s')" % (self.strCompressed(1))) 
+
+    def __add__(self, other):
+        """Emulate numeric objects through network aggregation"""
+        if self.prefixlen() != other.prefixlen():
+            raise ValueError, "Only networks with the same prefixlen can be added."
+        if self.prefixlen < 1:
+            raise ValueError, "Networks with a prefixlen longer than /1 can't be added."
+        if self.version() != other.version():
+            raise ValueError, "Only networks with the same IP version can be added."
+        if self > other:
+            # fixed by Skinny Puppy <skin_pup-IPy at happypoo.com>
+            return other.__add__(self)
+        else:
+            ret = IP(self.int())
+            ret._prefixlen = self.prefixlen() - 1 
+            return ret
+
+def parseAddress(ipstr):
+    """Parse a string and return the corrospondending IPaddress and the a guess of the IP version.
+
+    Following Forms ar recorgnized:
+    0x0123456789abcdef           # IPv4 if <= 0xffffffff else IPv6
+    123.123.123.123              # IPv4
+    123.123                      # 0-padded IPv4
+    1080:0000:0000:0000:0008:0800:200C:417A
+    1080:0:0:0:8:800:200C:417A
+    1080:0::8:800:200C:417A
+    ::1
+    ::
+    0:0:0:0:0:FFFF:129.144.52.38
+    ::13.1.68.3
+    ::FFFF:129.144.52.38
+    """
+
+    # TODO: refactor me!
+    if ipstr.startswith('0x'):
+        ret = long(ipstr[2:], 16)
+        if ret > 0xffffffffffffffffffffffffffffffffL:
+            raise ValueError, "%r: IP Address can't be bigger than 2^128" % (ipstr)
+        if ret < 0x100000000L:
+            return (ret, 4)
+        else:
+            return (ret, 6)
+            
+    if ipstr.find(':') != -1:
+        # assume IPv6
+        if ipstr.find(':::') != -1:
+            raise ValueError, "%r: IPv6 Address can't contain ':::'" % (ipstr)
+        hextets = ipstr.split(':')
+        if ipstr.find('.') != -1:
+            # this might be a mixed address like '0:0:0:0:0:0:13.1.68.3'
+            (v4, foo) = parseAddress(hextets[-1])
+            assert foo == 4
+            del(hextets[-1])
+            hextets.append(hex(v4 >> 16)[2:-1])
+            hextets.append(hex(v4 & 0xffff)[2:-1])
+        if len(hextets) > 8:
+            raise ValueError, "%r: IPv6 Address with more than 8 hexletts" % (ipstr)
+        if len(hextets) < 8:
+            if '' not in hextets:
+                raise ValueError, "%r IPv6 Address with less than 8 hexletts and without '::'" % (ipstr)
+            # catch :: at the beginning or end
+            if hextets.index('') < len(hextets) - 1 and hextets[hextets.index('')+1] == '':
+                hextets.remove('')
+            # catch '::'
+            if hextets.index('') < len(hextets) - 1 and hextets[hextets.index('')+1] == '':
+                hextets.remove('')
+            
+            for foo in range(9-len(hextets)):
+                hextets.insert(hextets.index(''), '0')
+            hextets.remove('')
+            if '' in hextets:
+                raise ValueError, "%r IPv6 Address may contain '::' only once" % (ipstr)
+        if '' in hextets:
+            raise ValueError, "%r IPv6 Address may contain '::' only if it has less than 8 hextets" % (ipstr)
+        num = ''
+        for x in hextets:
+            if len(x) < 4:
+                x = ((4 - len(x)) * '0') + x
+            if int(x, 16) < 0 or int(x, 16) > 0xffff: 
+                raise ValueError, "%r: single hextet must be 0 <= hextet <= 0xffff which isn't true for %s" % (ipstr, x)
+            num += x
+        return (long(num, 16), 6)
+
+    elif len(ipstr) == 32:
+        # assume IPv6 in pure hexadecimal notation
+        return (long(ipstr, 16), 6)
+    
+    elif  ipstr.find('.') != -1 or (len(ipstr) < 4 and int(ipstr) < 256):
+        # assume IPv4  ('127' gets interpreted as '127.0.0.0')
+        bytes = ipstr.split('.')
+        if len(bytes) > 4:
+            raise ValueError, "IPv4 Address with more than 4 bytes"
+        bytes += ['0'] * (4 - len(bytes))
+        bytes = [long(x) for x in bytes]
+        for x in bytes:
+            if x > 255 or x < 0:
+                raise ValueError, "%r: single byte must be 0 <= byte < 256" % (ipstr)
+        return ((bytes[0] << 24) + (bytes[1] << 16) + (bytes[2] << 8) + bytes[3], 4)
+
+    else:
+        # we try to interprete it as a decimal digit -
+        # this ony works for numbers > 255 ... others
+        # will be interpreted as IPv4 first byte
+        ret = long(ipstr)
+        if ret > 0xffffffffffffffffffffffffffffffffL:
+            raise ValueError, "IP Address cant be bigger than 2^128"
+        if ret <= 0xffffffffL:
+            return (ret, 4)
+        else:
+            return (ret, 6)
+
+
+def intToIp(ip, version):
+    """Transform an integer string into an IP address."""
+
+    # just to be sure and hoping for Python 2.22
+    ip = long(ip)
+
+    if ip < 0:
+        raise ValueError, "IPs can't be negative: %d" % (ip)
+    
+    ret = ''
+    if version == 4: 
+        if ip > 0xffffffffL:
+            raise ValueError, "IPv4 Addresses can't be larger than 0xffffffff: %s" % (hex(ip))
+        for l in range(4):
+            ret = str(ip & 0xffL) + '.' + ret
+            ip = ip >> 8;
+        ret = ret[:-1]
+    elif version == 6:
+        if ip > 0xffffffffffffffffffffffffffffffffL:
+            raise ValueError, "IPv6 Addresses can't be larger than 0xffffffffffffffffffffffffffffffff: %s" % (hex(ip))
+        l = '0' * 32 + hex(ip)[2:-1]
+        for x in range(1,33):
+            ret = l[-x] + ret
+            if x % 4 == 0:
+                ret = ':' + ret
+        ret = ret[1:]
+    else:
+        raise ValueError, "only IPv4 and IPv6 supported"
+            
+    return ret;
+
+def _ipVersionToLen(version):
+    """Return number of bits in address for a certain IP version.
+
+    >>> _ipVersionToLen(4)
+    32
+    >>> _ipVersionToLen(6)
+    128
+    >>> _ipVersionToLen(5)
+    Traceback (most recent call last):
+      File "<stdin>", line 1, in ?
+      File "IPy.py", line 1076, in _ipVersionToLen
+        raise ValueError, "only IPv4 and IPv6 supported"
+    ValueError: only IPv4 and IPv6 supported
+    """
+
+    if version == 4:
+        return 32
+    elif version == 6:
+        return 128
+    else:
+        raise ValueError, "only IPv4 and IPv6 supported"
+
+
+def _countFollowingZeros(l):
+    """Return Nr. of elements containing 0 at the beginning th the list."""
+    if len(l) == 0:
+        return 0
+    elif l[0] != 0:
+        return 0
+    else:
+        return 1 + _countFollowingZeros(l[1:])
+
+
+_BitTable = {'0': '0000', '1': '0001', '2': '0010', '3': '0011',
+            '4': '0100', '5': '0101', '6': '0110', '7': '0111',
+            '8': '1000', '9': '1001', 'a': '1010', 'b': '1011',
+            'c': '1100', 'd': '1101', 'e': '1110', 'f': '1111'}
+        
+def _intToBin(val):
+    """Return the binary representation of an integer as string."""
+
+    if val < 0:
+        raise ValueError, "Only positive Values allowed"
+    s = hex(val).lower()
+    ret = ''
+    if s[-1] == 'l':
+        s = s[:-1]
+    for x in s[2:]:
+        if __debug__:
+            if not _BitTable.has_key(x):
+                raise AssertionError, "hex() returned strange result"
+        ret += _BitTable[x]
+    # remove leading zeros
+    while ret[0] == '0' and len(ret) > 1:
+        ret = ret[1:]
+    return ret 
+
+def _count1Bits(num):
+    """Find the highest bit set to 1 in an integer."""
+    ret = 0
+    while num > 0:
+        num = num >> 1
+        ret += 1
+    return ret
+
+def _count0Bits(num):
+    """Find the highest bit set to 0 in an integer."""
+
+    # this could be so easy if _count1Bits(~long(num)) would work as excepted
+    num = long(num)
+    if num < 0:
+        raise ValueError, "Only positive Numbers please: %s" % (num)
+    ret = 0
+    while num > 0:
+        if num & 1 == 1:
+            break
+        num = num >> 1
+        ret += 1
+    return ret 
+
+    
+def _checkPrefix(ip, prefixlen, version):
+    """Check the validity of a prefix
+    
+    Checks if the variant part of a prefix only has 0s, and the length is
+    correct.
+
+    >>> _checkPrefix(0x7f000000L, 24, 4)
+    1
+    >>> _checkPrefix(0x7f000001L, 24, 4)
+    0
+    >>> repr(_checkPrefix(0x7f000001L, -1, 4))
+    'None'
+    >>> repr(_checkPrefix(0x7f000001L, 33, 4))
+    'None'
+    """
+
+    # TODO: unify this v4/v6/invalid code in a function
+    bits = _ipVersionToLen(version)
+    
+    if prefixlen < 0 or prefixlen > bits:
+        return None
+
+    if ip == 0: 
+        zbits = bits + 1
+    else:
+        zbits = _count0Bits(ip)
+    if zbits <  bits - prefixlen:
+        return 0
+    else:
+        return 1
+
+
+def _checkNetmask(netmask, masklen):
+    """Checks if a netmask is expressable as e prefixlen."""
+
+    num = long(netmask)
+    bits = masklen
+    
+    # remove zero bits at the end
+    while (num & 1) == 0:
+        num = num >> 1
+        bits -= 1
+        if bits == 0:
+            break
+    # now check if the rest consists only of ones
+    while bits > 0:
+        if (num & 1) == 0:
+            raise ValueError, "Netmask %s can't be expressed as an prefix." % (hex(netmask))
+        num = num >> 1
+        bits -= 1
+
+
+def _checkNetaddrWorksWithPrefixlen(net, prefixlen, version):
+    """Check if a base addess of e network is compatible with a prefixlen"""
+    if net & _prefixlenToNetmask(prefixlen, version) == net:
+        return 1
+    else:
+        return 0
+    
+
+def _netmaskToPrefixlen(netmask):
+    """Convert an Integer reprsenting a Netmask to an prefixlen.
+
+    E.g. 0xffffff00 (255.255.255.0) returns 24
+    """
+
+    netlen = _count0Bits(netmask)
+    masklen = _count1Bits(netmask)
+    _checkNetmask(netmask, masklen)
+    return masklen - netlen
+
+
+def _prefixlenToNetmask(prefixlen, version):
+    """Return a mask of n bits as a long integer.
+
+    From 'IP address conversion functions with the builtin socket module' by Alex Martelli
+    http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/66517
+    """
+    if prefixlen == 0:
+        return 0
+    elif prefixlen < 0:
+        raise ValueError, "Prefixlen must be > 0"
+    return ((2L<<prefixlen-1)-1) << (_ipVersionToLen(version) - prefixlen)
+         
+
+def _test():
+    import doctest, IPy
+    return doctest.testmod(IPy)
+
+if __name__ == "__main__":
+    _test()
+
+    t = [0xf0, 0xf00, 0xff00, 0xffff00, 0xffffff00L]
+    o = []
+    for x in t:
+        pass
+    x = 0L

Added: packages/ipy/branches/upstream/current/MANIFEST.in
URL: http://svn.debian.org/wsvn/python-modules/packages/ipy/branches/upstream/current/MANIFEST.in?rev=371&op=file
==============================================================================
--- packages/ipy/branches/upstream/current/MANIFEST.in (added)
+++ packages/ipy/branches/upstream/current/MANIFEST.in Mon May  1 12:03:34 2006
@@ -1,0 +1,1 @@
+recursive-include example

Added: packages/ipy/branches/upstream/current/README
URL: http://svn.debian.org/wsvn/python-modules/packages/ipy/branches/upstream/current/README?rev=371&op=file
==============================================================================
--- packages/ipy/branches/upstream/current/README (added)
+++ packages/ipy/branches/upstream/current/README Mon May  1 12:03:34 2006
@@ -1,0 +1,75 @@
+IPy is a Python module for handling IPv4 and IPv6 Addresses and Networks in
+a fashion similar to perl's Net::IP and friends. The IP class allows a
+comfortable parsing and handling for most notations in use for IPv4 and IPv6
+Addresses and Networks. 
+
+It enables code like this: 
+
+      >>> 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()
+      'RESERVED'
+    
+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
+      >>> 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
+      >>> print IP('1080:0:0:0:8:800:200C:417A')
+      1080:0000:0000:0000:0008:0800:200c:417a
+      >>> print IP('1080::8:800:200C:417A')
+      1080:0000:0000:0000:0008:0800:200c:417a
+      >>> print IP('::1')
+      0000:0000:0000:0000:0000:0000:0000:0001
+      >>> print IP('::13.1.68.3')
+      0000:0000:0000:0000:0000:0000:0d01:4403
+      >>> 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
+      >>> IP('10.0.0.0/24').strNormal(q)
+      '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'
+
+To install type 
+
+$ python setup.py install
+$ pydoc -w IPy
+$ cd test
+$ python test_IPy.py
+
+Read IPy.html for usage Instructions.
+
+IPy has been tested with python 2.2 and pyton 2.1.
+
+Further Information can be found at http://c0re.jp/c0de/IPy/ 
+  --drt at un.bewaff.net

Added: packages/ipy/branches/upstream/current/THANKS
URL: http://svn.debian.org/wsvn/python-modules/packages/ipy/branches/upstream/current/THANKS?rev=371&op=file
==============================================================================
--- packages/ipy/branches/upstream/current/THANKS (added)
+++ packages/ipy/branches/upstream/current/THANKS Mon May  1 12:03:34 2006
@@ -1,0 +1,4 @@
+Mark Johnston - bringing IPy to Python 2.3
+Shell, Hin-lik Hung - bring IPy to OpenBSD ports
+Samuel Krempp - fix __cmp__() bug
+Skinny Puppy - __add__() now always  returns a value

Added: packages/ipy/branches/upstream/current/build/lib/IPy.py
URL: http://svn.debian.org/wsvn/python-modules/packages/ipy/branches/upstream/current/build/lib/IPy.py?rev=371&op=file
==============================================================================
--- packages/ipy/branches/upstream/current/build/lib/IPy.py (added)
+++ packages/ipy/branches/upstream/current/build/lib/IPy.py Mon May  1 12:03:34 2006
@@ -1,0 +1,1262 @@
+""" IPy - class and tools for handling of IPv4 and IPv6 Addresses and Networks.
+
+$Id: IPy.py,v 1.10 2002/05/16 05:22:26 drt Exp $
+
+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 bei RIPE's Perl module NET::IP's interface but
+doesn't share the Implementation. It doesn't share non-CIDR netmasks,
+so funky stuff lixe a netmask 0xffffff0f can't be done here.
+
+    >>> 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'
+
+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
+    >>> 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
+    >>> print IP('1080:0:0:0:8:800:200C:417A')
+    1080:0000:0000:0000:0008:0800:200c:417a
+    >>> print IP('1080::8:800:200C:417A')
+    1080:0000:0000:0000:0008:0800:200c:417a
+    >>> print IP('::1')
+    0000:0000:0000:0000:0000:0000:0000:0001
+    >>> print IP('::13.1.68.3')
+    0000:0000:0000:0000:0000:0000:0d01:4403
+    >>> 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
+
+Nearly all class methods which return a string have an optional
+parameter 'wantprefixlen' which controlles if the prefixlen or netmask
+is printed. Per default the prefilen is always shown if the net
+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 fiddeling with the class members
+
+NoPrefixForSingleIp
+WantPrefixLen
+
+    >>> 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
+                
+
+Further Information might be available at http://c0re.jp/c0de/IPy/
+
+Hacked 2001 by drt at un.bewaff.net
+
+TODO:
+      * better comparison (__cmp__ and friends)
+      * tests for __cmp__
+      * always write hex values lowercase
+      * interpret 2001:1234:5678:1234/64 as 2001:1234:5678:1234::/64
+      * move size in bits into class variables to get rid of some "if self._ipversion ..."
+      * support for base85 encoding
+      * support for output of IPv6 encoded IPv4 Addresses
+      * update address type tables      
+      * first-last notation should be allowed for IPv6
+      * add IPv6 docstring examples
+      * check better for negative parameters
+      * add addition / aggregation
+      * move reverse name stuff out of the classes and refactor it
+      * support for aggregation of more than two nets at once
+      * support for aggregation with "holes"
+      * support for finding common prefix
+      * '>>' and '<<' for prefix manipulation
+      * add our own exceptions instead ValueError all the time
+      * rename checkPrefix to checkPrefixOk
+      * add more documentation and doctests
+      * refactor
+"""
+
+import types
+
+# Definition of the Ranges for IPv4 IPs
+# this should include www.iana.org/assignments/ipv4-address-space
+# and www.iana.org/assignments/multicast-addresses
+IPv4ranges = {
+    '0'	   	        : 'PUBLIC',   # fall back
+    '00000000'		: 'PRIVATE',  # 0/8
+    '00001010'		: 'PRIVATE',  # 10/8
+    '01111111'		: 'PRIVATE',  # 127.0/8
+    '1'		        : 'PUBLIC',   # fall back
+    '101011000001'      : 'PRIVATE',  # 172.16/12
+    '1100000010101000'	: 'PRIVATE',  # 192.168/16
+    '11011111'		: 'RESERVED', # 223/8
+    '111'	        : 'RESERVED'  # 224/3
+    }
+
+# Definition of the Ranges for IPv6 IPs
+# see also www.iana.org/assignments/ipv6-address-space,
+# www.iana.org/assignments/ipv6-tla-assignments,
+# www.iana.org/assignments/ipv6-multicast-addresses,
+# www.iana.org/assignments/ipv6-anycast-addresses
+IPv6ranges = {
+    '00000000'              : 'RESERVED',       # ::/8
+    '00000001'              : 'UNASSIGNED',     # 100::/8
+    '0000001'               : 'NSAP',           # 200::/7
+    '0000010'               : 'IPX',            # 400::/7
+    '0000011'               : 'UNASSIGNED',     # 600::/7   
+    '00001'                 : 'UNASSIGNED',     # 800::/5
+    '0001'                  : 'UNASSIGNED',     # 1000::/4
+    '0010000000000000'      : 'RESERVED',       # 2000::/16 Reserved
+    '0010000000000001'      : 'ASSIGNABLE',     # 2001::/16 Sub-TLA Assignments [RFC2450]
+    '00100000000000010000000': 'ASSIGNABLE IANA',  # 2001:0000::/29 - 2001:01F8::/29 IANA
+    '00100000000000010000001': 'ASSIGNABLE APNIC', # 2001:0200::/29 - 2001:03F8::/29 APNIC
+    '00100000000000010000010': 'ASSIGNABLE ARIN',  # 2001:0400::/29 - 2001:05F8::/29 ARIN
+    '00100000000000010000011': 'ASSIGNABLE RIPE',  # 2001:0600::/29 - 2001:07F8::/29 RIPE NCC
+    '0010000000000010'      : '6TO4',           # 2002::/16 "6to4" [RFC3056]
+    '0011111111111110'      : '6BONE',          # 3FFE::/16 6bone Testing [RFC2471]
+    '0011111111111111'      : 'RESERVED',       # 3FFF::/16 Reserved
+    '010'                   : 'GLOBAL-UNICAST', # 4000::/3              
+    '011'                   : 'UNASSIGNED',     # 6000::/3
+    '100'                   : 'GEO-UNICAST',    # 8000::/3
+    '101'                   : 'UNASSIGNED',     # A000::/3
+    '110'                   : 'UNASSIGNED',     # C000::/3
+    '1110'                  : 'UNASSIGNED',     # E000::/4
+    '11110'                 : 'UNASSIGNED',     # F000::/5
+    '111110'                : 'UNASSIGNED',     # F800::/6
+    '1111110'               : 'UNASSIGNED',     # FC00::/7
+    '111111100'             : 'UNASSIGNED',     # FE00::/9
+    '1111111010'            : 'LINKLOCAL',      # FE80::/10
+    '1111111011'            : 'SITELOCAL',      # FEC0::/10
+    '11111111'              : 'MULTICAST',      # FF00::/8
+    '0' * 96                : 'IPV4COMP',       # ::/96
+    '0' * 80 + '1' * 16     : 'IPV4MAP',        # ::FFFF:0:0/96
+    '0' * 128               : 'UNSPECIFIED',    # ::/128
+    '0' * 127 + '1'         : 'LOOPBACK'        # ::1/128
+    }
+
+
+class IPint:
+    """Handling of IP addresses returning integers.
+
+    Use class IP instead because some features are not implemented for
+    IPint."""
+    
+    def __init__(self, data, ipversion = 0):
+        """Create an instance of an IP object.
+        
+        Data can be a network specification or a single IP. IP
+        Addresses can be specified in all forms understood by
+        parseAddress.() the size of a network can be specified as
+
+        /prefixlen        a.b.c.0/24               2001:658:22a:cafe::/64
+        -lastIP           a.b.c.0-a.b.c.255        2001:658:22a:cafe::-2001:658:22a:cafe:ffff:ffff:ffff:ffff
+        /decimal netmask  a.b.c.d/255.255.255.0    not supported for IPv6
+
+        If no size specification is given a size of 1 address (/32 for
+        IPv4 and /128 for IPv6) is assumed.
+
+        >>> 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
+
+        See module documentation for more examples.
+        """
+
+        self.NoPrefixForSingleIp = 1  # Print no Prefixlen for /32 and /128
+        self.WantPrefixLen = None     # Do we want prefix printed by default? see _printPrefix()
+        
+        netbits = 0
+        prefixlen = -1
+        
+        # handling of non string values in constructor
+        if type(data) == types.IntType or type(data) == types.LongType:
+            self.ip = long(data)
+            if ipversion == 0:
+                if self.ip < 0x100000000L:
+                    ipversion = 4
+                else:
+                    ipversion = 6
+            if ipversion == 4:
+                prefixlen = 32
+            elif ipversion == 6:
+                prefixlen = 128
+            else:
+                raise ValueError, "only IPv4 and IPv6 supported"
+            self._ipversion = ipversion
+            self._prefixlen = prefixlen
+        # handle IP instance as an parameter
+        elif isinstance(data, IPint):
+            self._ipversion = data._ipversion
+            self._prefixlen = data._prefixlen
+            self.ip = data.ip
+        else:
+            # TODO: refactor me!
+            # splitting of a string into IP and prefixlen et. al.
+            x = data.split('-')
+            if len(x) == 2:
+                # a.b.c.0-a.b.c.255 specification ?
+                (ip, last) = x
+                (self.ip, parsedVersion) = parseAddress(ip)
+                if parsedVersion != 4:
+                    raise ValueError, "first-last notation only allowed for IPv4"
+                (last, lastversion) = parseAddress(last)
+                if lastversion != 4:
+                    raise ValueError, "last address should be IPv4, too"
+                if last < self.ip:
+                    raise ValueError, "last address should be larger than first"
+                size = last - self.ip
+                netbits = _count1Bits(size)
+            elif len(x) == 1:    
+                x = data.split('/')
+                # if no prefix is given use defaults
+                if len(x) == 1:
+                    ip = x[0]
+                    prefixlen = -1
+                elif len(x) > 2:
+                    raise ValueError, "only one '/' allowed in IP Address"
+                else:
+                    (ip, prefixlen) = x
+                    if prefixlen.find('.') != -1:
+                        # check if the user might have used a netmask like
+                        # a.b.c.d/255.255.255.0
+                        (netmask, vers) = parseAddress(prefixlen)
+                        if vers != 4:
+                            raise ValueError, "netmask must be IPv4"
+                        prefixlen = _netmaskToPrefixlen(netmask)                         
+            elif len(x) > 2:
+                raise ValueError, "only one '-' allowed in IP Address"
+            else:
+                raise ValueError, "can't parse"
+
+            (self.ip, parsedVersion) = parseAddress(ip)
+            if ipversion == 0:
+                ipversion = parsedVersion
+            if prefixlen == -1:
+                if ipversion == 4:
+                    prefixlen = 32 - netbits
+                elif ipversion == 6:
+                    prefixlen = 128 - netbits
+                else:
+                    raise ValueError, "only IPv4 and IPv6 supported"
+            self._ipversion = ipversion
+            self._prefixlen = int(prefixlen)
+
+            if not _checkNetaddrWorksWithPrefixlen(self.ip, self._prefixlen, self._ipversion):
+                raise ValueError, "%s goes not well with prefixlen %d" % (hex(self.ip), self._prefixlen) 
+                
+
+    def int(self):
+        """Return the first / base / network addess as an (long) integer.
+
+        The same as IP[0].
+
+        >>> hex(IP('10.0.0.0/8').int())
+        '0xA000000L'
+        """
+        return self.ip
+
+    def version(self):
+        """Return the IP version of this Object.
+
+        >>> IP('10.0.0.0/8').version()
+        4
+        >>> IP('::1').version()
+        6
+        """
+        return self._ipversion
+
+    def prefixlen(self):
+        """Returns Network Prefixlen.
+
+        >>> IP('10.0.0.0/8').prefixlen()
+        8
+        """
+        return self._prefixlen
+
+    def net(self):
+        """Return the base (first) address of a network as an (long) integer."""
+
+        return self.int()
+
+    def broadcast(self):
+        """Return the broadcast (last) address of a network as an (long) integer.
+
+        The same as IP[-1]."""
+        return self.int() + self.len() - 1
+
+    def _printPrefix(self, want):
+        """Prints Prefixlen/Netmask.
+
+        Not really. In fact it is our universal Netmask/Prefixlen printer.
+        This is considered an internel function.
+
+        want == 0 / None        don't return anything    1.2.3.0
+        want == 1               /prefix                  1.2.3.0/24
+        want == 2               /netmask                 1.2.3.0/255.255.255.0
+        want == 3               -lastip                  1.2.3.0-1.2.3.255
+        """
+
+        if (self._ipversion == 4 and self._prefixlen == 32) or \
+           (self._ipversion == 6 and self._prefixlen == 128): 
+            if self.NoPrefixForSingleIp:
+                want = 0
+        if want == None:
+            want = self.WantPrefixLen
+            if want == None:
+                want = 1
+        if want:
+            if want == 2:
+                # this should work wit IP and IPint
+                netmask = self.netmask()
+                if type(netmask) != types.IntType and type(netmask) != types.LongType:
+                    netmask = netmask.int()
+                return "/%s" % (intToIp(netmask, self._ipversion))
+            elif want == 3:
+                return "-%s" % (intToIp(self.ip + self.len() - 1, self._ipversion))
+            else:
+                # default
+                return "/%d" % (self._prefixlen)
+        else:
+            return ''
+
+        # We have different Favours to convert to:
+        # strFullsize   127.0.0.1    2001:0658:022a:cafe:0200:c0ff:fe8d:08fa
+        # strNormal     127.0.0.1    2001:658:22a:cafe:200:c0ff:fe8d:08fa
+        # strCompressed 127.0.0.1    2001:658:22a:cafe::1
+        # strHex        0x7F000001L  0x20010658022ACAFE0200C0FFFE8D08FA
+        # strDec        2130706433   42540616829182469433547974687817795834
+
+    def strBin(self, wantprefixlen = None): 
+        """Return a string representation as a binary value.
+
+        >>> print IP('127.0.0.1').strBin()
+        01111111000000000000000000000001
+        """
+
+
+        if self._ipversion == 4:
+            bits = 32 
+        elif self._ipversion == 6:
+            bits = 128
+        else:
+            raise ValueError, "only IPv4 and IPv6 supported"
+
+        if self.WantPrefixLen == None and wantprefixlen == None:
+            wantprefixlen = 0
+        ret = _intToBin(self.ip)
+        return  '0' * (bits - len(ret)) + ret + self._printPrefix(wantprefixlen)
+
+    def strCompressed(self, wantprefixlen = None):
+        """Return a string representation in compressed format using '::' Notation.
+
+        >>> print IP('127.0.0.1').strCompressed()
+        127.0.0.1
+        >>> print IP('2001:0658:022a:cafe:0200::1').strCompressed()
+        2001:658:22a:cafe:200::1
+        """
+                
+        if self.WantPrefixLen == None and wantprefixlen == None:
+            wantprefixlen = 1
+            
+        if self._ipversion == 4:
+            return self.strFullsize(wantprefixlen)
+        else:
+            # find the longest sequence of '0'
+            hextets = [int(x, 16) for x in self.strFullsize(0).split(':')]
+            # every element of followingzeros will contain the number of zeros
+            # following the corrospondending element of hextetes
+            followingzeros = [0] * 8
+            for i in range(len(hextets)):
+                followingzeros[i] = _countFollowingZeros(hextets[i:])
+            # compressionpos is the position where we can start removing zeros
+            compressionpos = followingzeros.index(max(followingzeros))
+            if max(followingzeros) > 1:
+                # genererate string with the longest number of zeros cut out
+                # now we need hextets as strings
+                hextets = [x for x in self.strNormal(0).split(':')]
+                while compressionpos < len(hextets) and hextets[compressionpos] == '0':
+                    del(hextets[compressionpos])
+                hextets.insert(compressionpos, '')
+                if compressionpos + 1 >= len(hextets):
+                    hextets.append('')
+                if compressionpos == 0:
+                    hextets = [''] + hextets
+                return ':'.join(hextets) + self._printPrefix(wantprefixlen)
+            else:
+                return self.strNormal() + self._printPrefix(wantprefixlen)
+
+    def strNormal(self, wantprefixlen = None):
+        """Return a string representation in the usual format.
+
+        >>> print IP('127.0.0.1').strNormal()
+        127.0.0.1
+        >>> print IP('2001:0658:022a:cafe:0200::1').strNormal()
+        2001:658:22a:cafe:200:0:0:1
+        """
+
+        if self.WantPrefixLen == None and wantprefixlen == None:
+            wantprefixlen = 1
+        
+        if self._ipversion == 4:
+            ret = self.strFullsize(0) 
+        elif self._ipversion == 6:
+            ret = ':'.join([hex(x)[2:] for x in [int(x, 16) for x in self.strFullsize(0).split(':')]])
+        else:
+            raise ValueError, "only IPv4 and IPv6 supported"
+
+            
+        
+        return ret + self._printPrefix(wantprefixlen)
+
+    def strFullsize(self, wantprefixlen = None):
+        """Return a string representation in the non mangled format.
+
+        >>> print IP('127.0.0.1').strFullsize()
+        127.0.0.1
+        >>> print IP('2001:0658:022a:cafe:0200::1').strFullsize()
+        2001:0658:022a:cafe:0200:0000:0000:0001
+        """
+
+        if self.WantPrefixLen == None and wantprefixlen == None:
+            wantprefixlen = 1
+            
+        return intToIp(self.ip, self._ipversion).lower() + self._printPrefix(wantprefixlen)
+
+    def strHex(self, wantprefixlen = None):
+        """Return a string representation in hex format.
+
+        >>> print IP('127.0.0.1').strHex()
+        0x7F000001
+        >>> print IP('2001:0658:022a:cafe:0200::1').strHex()
+        0x20010658022ACAFE0200000000000001
+        """
+
+        if self.WantPrefixLen == None and wantprefixlen == None:
+            wantprefixlen = 0
+
+        x = hex(self.ip)
+        if x[-1] == 'L':
+            x = x[:-1]
+        return x + self._printPrefix(wantprefixlen)
+
+    def strDec(self, wantprefixlen = None):
+        """Return a string representation in decimal format.
+
+        >>> print IP('127.0.0.1').strDec()
+        2130706433
+        >>> print IP('2001:0658:022a:cafe:0200::1').strDec()
+        42540616829182469433547762482097946625
+        """
+
+        if self.WantPrefixLen == None and wantprefixlen == None:
+            wantprefixlen = 0
+
+        x =  str(self.ip)
+        if x[-1] == 'L':
+            x = x[:-1]
+        return x + self._printPrefix(wantprefixlen)
+
+    def iptype(self):
+        """Return a description of the IP type ('PRIVATE', 'RESERVERD', etc).
+
+        >>> print IP('127.0.0.1').iptype()
+        PRIVATE
+        >>> print IP('192.168.1.1').iptype()
+        PRIVATE
+        >>> print IP('195.185.1.2').iptype()
+        PUBLIC
+        >>> print IP('::1').iptype()
+        LOOPBACK
+        >>> print IP('2001:0658:022a:cafe:0200::1').iptype()
+        ASSIGNABLE RIPE
+
+        The type information for IPv6 is out of sync with reality.
+        """
+
+        # this could be greatly improved
+
+        if self._ipversion == 4:
+            iprange = IPv4ranges 
+        elif self._ipversion == 6:
+            iprange = IPv6ranges 
+        else:
+            raise ValueError, "only IPv4 and IPv6 supported"
+
+        bits = self.strBin()
+        for i in range(len(bits), 0, -1):
+            if iprange.has_key(bits[:i]):
+                return iprange[bits[:i]]
+        return "unknown"
+
+
+    def netmask(self):
+        """Return netmask as an integer.
+
+        >>> print hex(IP('195.185.0.0/16').netmask().int())
+        0xFFFF0000L
+        """
+
+        # TODO: unify with prefixlenToNetmask?
+        if self._ipversion == 4:
+            locallen = 32 - self._prefixlen
+        elif self._ipversion == 6:
+            locallen = 128 - self._prefixlen
+        else:
+            raise ValueError, "only IPv4 and IPv6 supported"
+
+        return ((2L ** self._prefixlen) - 1) << locallen
+
+
+    def strNetmask(self):
+        """Return netmask as an string. Mostly useful for IPv6.
+
+        >>> print IP('195.185.0.0/16').strNetmask()
+        255.255.0.0
+        >>> print IP('2001:0658:022a:cafe::0/64').strNetmask()
+        /64
+        """
+
+        # TODO: unify with prefixlenToNetmask?
+        if self._ipversion == 4:
+            locallen = 32 - self._prefixlen
+            return intToIp(((2L ** self._prefixlen) - 1) << locallen, 4)
+        elif self._ipversion == 6:
+            locallen = 128 - self._prefixlen
+            return "/%d" % self._prefixlen
+        else:
+            raise ValueError, "only IPv4 and IPv6 supported"
+
+    def len(self):
+        """Return the length of an subnet.
+
+        >>> print IP('195.185.1.0/28').len()
+        16
+        >>> print IP('195.185.1.0/24').len()
+        256
+        """
+
+        if self._ipversion == 4:
+            locallen = 32 - self._prefixlen
+        elif self._ipversion == 6:
+            locallen = 128 - self._prefixlen
+        else:
+            raise ValueError, "only IPv4 and IPv6 supported"
+
+        return 2L ** locallen 
+
+
+    def __len__(self):
+        """Return the length of an subnet.
+
+        Called to implement the built-in function len().
+        It breaks with IPv6 Networks. Anybody knows how to fix this."""
+
+        # Python < 2.2 has this silly restriction which breaks IPv6
+        # how about Python >= 2.2 ... ouch - it presists!
+    
+        return int(self.len())
+
+
+    def __getitem__(self, key):
+        """Called to implement evaluation of self[key].
+        
+        >>> ip=IP('127.0.0.0/30')
+        >>> for x in ip:
+        ...  print hex(x.int())
+        ...
+        0x7F000000L
+        0x7F000001L
+        0x7F000002L
+        0x7F000003L
+        >>> hex(ip[2].int())
+        '0x7F000002L'
+        >>> hex(ip[-1].int())
+        '0x7F000003L'
+        """
+
+        if type(key) != types.IntType and type(key) != types.LongType:
+            raise TypeError
+        if abs(key) >= self.len():
+            raise IndexError
+        if key < 0:
+            key = self.len() - abs(key)
+
+        return self.ip + long(key)
+
+    
+
+    def __contains__(self, item):
+        """Called to implement membership test operators.
+
+        Should return true if item is in self, false otherwise. Item
+        can be other IP-objects, strings or ints.
+
+        >>> print IP('195.185.1.1').strHex()
+        0xC3B90101
+        >>> 0xC3B90101L in IP('195.185.1.0/24')
+        1
+        >>> '127.0.0.1' in IP('127.0.0.0/24')
+        1
+        >>> IP('127.0.0.0/24') in IP('127.0.0.0/25')
+        0
+        """
+
+        item = IP(item)
+        if item.ip >= self.ip and item.ip < self.ip + self.len() - item.len() + 1:
+            return 1
+        else:
+            return 0
+
+
+    def overlaps(self, item):
+        """Check if two IP address ranges overlap.
+
+        Returns 0 if the two ranged don't overlap, 1 if the given
+        range overlaps at the end and -1 if it does at the beginning.
+
+        >>> IP('192.168.0.0/23').overlaps('192.168.1.0/24')
+        1
+        >>> IP('192.168.0.0/23').overlaps('192.168.1.255')
+        1
+        >>> IP('192.168.0.0/23').overlaps('192.168.2.0')
+        0
+        >>> IP('192.168.1.0/24').overlaps('192.168.0.0/23')
+        -1
+        """
+
+        item = IP(item)
+        if item.ip >= self.ip and item.ip < self.ip + self.len():
+            return 1
+        elif self.ip >= item.ip and self.ip < item.ip + item.len():
+            return -1
+        else:
+            return 0
+
+    
+    def __str__(self):
+        """Dispatch to the prefered String Representation.
+
+        Used to implement str(IP)."""
+
+        return self.strFullsize()
+
+
+    def __repr__(self):
+        """Print a representation of the Object.
+
+        Used to implement repr(IP). Returns a string which evaluates
+        to an identical Object (without the wnatprefixlen stuff - see
+        module docstring.
+
+        >>> print repr(IP('10.0.0.0/24'))
+        IP('10.0.0.0/24')
+        """
+
+        return("IPint('%s')" % (self.strCompressed(1))) 
+
+
+    def __cmp__(self, other):
+        """Called by comparison operations.
+
+        Should return a negative integer if self < other, zero if self
+        == other, a positive integer if self > other.
+
+        Networks with different prefixlen are considered non-equal.
+        Networks with the same prefixlen and differing addresses are
+        considered non equal but are compared by thair base address
+        integer value to aid sorting of IP objects.
+
+        The Version of Objects is not put into consideration.
+
+        >>> IP('10.0.0.0/24') > IP('10.0.0.0')
+        1
+        >>> IP('10.0.0.0/24') < IP('10.0.0.0')
+        0
+        >>> IP('10.0.0.0/24') < IP('12.0.0.0/24')
+        1
+        >>> IP('10.0.0.0/24') > IP('12.0.0.0/24')
+        0
+
+        """
+
+        # Im not really sure if this is "the right thing to do"
+        if self._prefixlen < other.prefixlen():
+            return (other.prefixlen() - self._prefixlen) 
+        elif self._prefixlen > other.prefixlen():
+
+            # Fixed bySamuel Krempp <krempp at crans.ens-cachan.fr>:
+            
+            # The bug is quite obvious really (as 99% bugs are once
+            # spotted, isn't it ? ;-) Because of precedence of
+            # multiplication by -1 over the substraction, prefixlen
+            # differences were causing the __cmp__ function to always
+            # return positive numbers, thus the function was failing
+            # the basic assumptions for a __cmp__ function.
+
+            # Namely we could have (a > b AND b > a), when the
+            # prefixlen of a and b are different.  (eg let
+            # a=IP("1.0.0.0/24"); b=IP("2.0.0.0/16");) thus, anything
+            # could happen when launching a sort algorithm..
+            # everything's in order with the trivial, attached patch.
+                                             
+            return (self._prefixlen - other.prefixlen()) * -1
+        else:
+            if self.ip < other.ip:
+                return -1 
+            elif self.ip > other.ip:
+                return 1
+            else:
+                return 0
+        
+     
+    def __hash__(self):
+        """Called for the key object for dictionary operations, and by
+        the built-in function hash()  Should return a 32-bit integer
+        usable as a hash value for dictionary operations. The only
+        required property is that objects which compare equal have the
+        same hash value
+
+        >>> hex(IP('10.0.0.0/24').__hash__())
+        '0xf5ffffe7'
+        """
+
+        hash = int(-1)
+        ip = self.ip
+        while ip > 0:
+            hash = hash ^ (ip & 0x7fffffff)
+            ip = ip >> 32
+        hash = hash ^ self._prefixlen
+        return int(hash)
+
+
+class IP(IPint):
+    """Class for handling IP Addresses and Networks."""
+
+    def net(self):
+        """Return the base (first) address of a network as an IP object.
+
+        The same as IP[0].
+
+        >>> IP('10.0.0.0/8').net()
+        IP('10.0.0.0')
+        """
+        return IP(IPint.net(self))
+
+    def broadcast(self):
+        """Return the broadcast (last) address of a network as an IP object.
+
+        The same as IP[-1].
+
+        >>> IP('10.0.0.0/8').broadcast()
+        IP('10.255.255.255')
+        """
+        return IP(IPint.broadcast(self))
+
+    def netmask(self):
+        """Return netmask as an IP object.
+
+        >>> IP('10.0.0.0/8').netmask()
+        IP('255.0.0.0')
+         """
+        return IP(IPint.netmask(self))
+
+
+    def reverseNames(self):
+        """Return a list with values forming the reverse lookup.
+
+        >>> IP('213.221.113.87/32').reverseNames()
+        ['87.113.221.213.in-addr.arpa.']
+        >>> IP('213.221.112.224/30').reverseNames()
+        ['224.112.221.213.in-addr.arpa.', '225.112.221.213.in-addr.arpa.', '226.112.221.213.in-addr.arpa.', '227.112.221.213.in-addr.arpa.']
+        >>> IP('127.0.0.0/24').reverseNames()
+        ['0.0.127.in-addr.arpa.']
+        >>> IP('127.0.0.0/23').reverseNames()
+        ['0.0.127.in-addr.arpa.', '1.0.127.in-addr.arpa.']
+        >>> IP('127.0.0.0/16').reverseNames()
+        ['0.127.in-addr.arpa.']
+        >>> IP('127.0.0.0/15').reverseNames()
+        ['0.127.in-addr.arpa.', '1.127.in-addr.arpa.']
+        >>> IP('128.0.0.0/8').reverseNames()
+        ['128.in-addr.arpa.']
+        >>> IP('128.0.0.0/7').reverseNames()
+        ['128.in-addr.arpa.', '129.in-addr.arpa.']
+        
+        """
+
+        if self._ipversion == 4:
+            ret =[]
+            # TODO: Refactor. Add support for IPint objects
+            if self.len() < 2**8:
+                for x in self:
+                    ret.append(x.reverseName())
+            elif self.len() < 2**16L:
+                for i in range(0, self.len(), 2**8):
+                    ret.append(self[i].reverseName()[2:])
+            elif self.len() < 2**24L:
+                for i in range(0, self.len(), 2**16):
+                    ret.append(self[i].reverseName()[4:])
+            else:
+                for i in range(0, self.len(), 2**24):
+                    ret.append(self[i].reverseName()[6:])
+            return ret
+        elif self._ipversion == 6:
+            s = hex(self.ip)[2:].lower()
+            if s[-1] == 'l':
+                s = s[:-1]
+            if self._prefixlen % 4 != 0:
+                raise NotImplementedError, "can't create IPv6 reverse names at sub nibble level"
+            s = list(s)
+            s.reverse()
+            s = '.'.join(s)
+            first_nibble_index = int(32 - (self._prefixlen / 4)) * 2
+            return ["%s.ip6.int." % s[first_nibble_index:]]
+        else:
+            raise ValueError, "only IPv4 and IPv6 supported"
+        
+        
+
+    def reverseName(self):
+        """Return the value for reverse lookup/PTR records as RfC 2317 look alike.
+
+        RfC 2317 is an ugly hack which only works for sub-/24 e.g. not
+        for /23. Do not use it. Better set up a Zone for every
+        address. See reverseName for a way to arcive that.
+
+        >>> print IP('195.185.1.1').reverseName()
+        1.1.185.195.in-addr.arpa.
+        >>> print IP('195.185.1.0/28').reverseName()
+        0-15.1.185.195.in-addr.arpa.
+        """
+
+        if self._ipversion == 4:
+            s = self.strFullsize(0)
+            s = s.split('.')
+            s.reverse()
+            first_byte_index = int(4 - (self._prefixlen / 8)) 
+            if self._prefixlen % 8 != 0:
+                nibblepart = "%s-%s" % (s[3-(self._prefixlen / 8)], intToIp(self.ip + self.len() - 1, 4).split('.')[-1])
+                if nibblepart[-1] == 'l':
+                    nibblepart = nibblepart[:-1]
+                nibblepart += '.'
+            else:
+                nibblepart = ""
+
+            s = '.'.join(s[first_byte_index:])
+            return "%s%s.in-addr.arpa." % (nibblepart, s)
+
+        elif self._ipversion == 6:
+            s = hex(self.ip)[2:].lower()
+            if s[-1] == 'l':
+                s = s[:-1]
+            if self._prefixlen % 4 != 0:
+                nibblepart = "%s-%s" % (s[self._prefixlen:], hex(self.ip + self.len() - 1)[2:].lower())
+                if nibblepart[-1] == 'l':
+                    nibblepart = nibblepart[:-1]
+                nibblepart += '.'
+            else:
+                nibblepart = ""
+            s = list(s)
+            s.reverse()
+            s = '.'.join(s)
+            first_nibble_index = int(32 - (self._prefixlen / 4)) * 2
+            return "%s%s.ip6.int." % (nibblepart, s[first_nibble_index:])
+        else:
+            raise ValueError, "only IPv4 and IPv6 supported"
+
+    def __getitem__(self, key):
+        """Called to implement evaluation of self[key].
+        
+        >>> ip=IP('127.0.0.0/30')
+        >>> for x in ip:
+        ...  print str(x)
+        ...
+        127.0.0.0
+        127.0.0.1
+        127.0.0.2
+        127.0.0.3
+        >>> print str(ip[2])
+        127.0.0.2
+        >>> print str(ip[-1])
+        127.0.0.3
+        """
+        return IP(IPint.__getitem__(self, key))
+
+    def __repr__(self):
+        """Print a representation of the Object.
+
+        >>> IP('10.0.0.0/8')
+        IP('10.0.0.0/8')
+        """
+
+        return("IP('%s')" % (self.strCompressed(1))) 
+
+    def __add__(self, other):
+        """Emulate numeric objects through network aggregation"""
+        if self.prefixlen() != other.prefixlen():
+            raise ValueError, "Only networks with the same prefixlen can be added."
+        if self.prefixlen < 1:
+            raise ValueError, "Networks with a prefixlen longer than /1 can't be added."
+        if self.version() != other.version():
+            raise ValueError, "Only networks with the same IP version can be added."
+        if self > other:
+            # fixed by Skinny Puppy <skin_pup-IPy at happypoo.com>
+            return other.__add__(self)
+        else:
+            ret = IP(self.int())
+            ret._prefixlen = self.prefixlen() - 1 
+            return ret
+
+def parseAddress(ipstr):
+    """Parse a string and return the corrospondending IPaddress and the a guess of the IP version.
+
+    Following Forms ar recorgnized:
+    0x0123456789abcdef           # IPv4 if <= 0xffffffff else IPv6
+    123.123.123.123              # IPv4
+    123.123                      # 0-padded IPv4
+    1080:0000:0000:0000:0008:0800:200C:417A
+    1080:0:0:0:8:800:200C:417A
+    1080:0::8:800:200C:417A
+    ::1
+    ::
+    0:0:0:0:0:FFFF:129.144.52.38
+    ::13.1.68.3
+    ::FFFF:129.144.52.38
+    """
+
+    # TODO: refactor me!
+    if ipstr.startswith('0x'):
+        ret = long(ipstr[2:], 16)
+        if ret > 0xffffffffffffffffffffffffffffffffL:
+            raise ValueError, "%r: IP Address can't be bigger than 2^128" % (ipstr)
+        if ret < 0x100000000L:
+            return (ret, 4)
+        else:
+            return (ret, 6)
+            
+    if ipstr.find(':') != -1:
+        # assume IPv6
+        if ipstr.find(':::') != -1:
+            raise ValueError, "%r: IPv6 Address can't contain ':::'" % (ipstr)
+        hextets = ipstr.split(':')
+        if ipstr.find('.') != -1:
+            # this might be a mixed address like '0:0:0:0:0:0:13.1.68.3'
+            (v4, foo) = parseAddress(hextets[-1])
+            assert foo == 4
+            del(hextets[-1])
+            hextets.append(hex(v4 >> 16)[2:-1])
+            hextets.append(hex(v4 & 0xffff)[2:-1])
+        if len(hextets) > 8:
+            raise ValueError, "%r: IPv6 Address with more than 8 hexletts" % (ipstr)
+        if len(hextets) < 8:
+            if '' not in hextets:
+                raise ValueError, "%r IPv6 Address with less than 8 hexletts and without '::'" % (ipstr)
+            # catch :: at the beginning or end
+            if hextets.index('') < len(hextets) - 1 and hextets[hextets.index('')+1] == '':
+                hextets.remove('')
+            # catch '::'
+            if hextets.index('') < len(hextets) - 1 and hextets[hextets.index('')+1] == '':
+                hextets.remove('')
+            
+            for i in range(9-len(hextets)):
+                hextets.insert(hextets.index(''), '0')
+            hextets.remove('')
+            if '' in hextets:
+                raise ValueError, "%r IPv6 Address may contain '::' only once" % (ipstr)
+        if '' in hextets:
+            raise ValueError, "%r IPv6 Address may contain '::' only if it has less than 8 hextets" % (ipstr)
+        num = ''
+        for x in hextets:
+            if len(x) < 4:
+                x = ((4 - len(x)) * '0') + x
+            if int(x, 16) < 0 or int(x, 16) > 0xffff: 
+                raise ValueError, "%r: single hextet must be 0 <= hextet <= 0xffff which isn't true for %s" % (ipstr, x)
+            num += x
+        return (long(num, 16), 6)
+
+    elif len(ipstr) == 32:
+        # assume IPv6 in pure hexadecimal notation
+        return (long(ipstr, 16), 6)
+    
+    elif  ipstr.find('.') != -1 or (len(ipstr) < 4 and int(ipstr) < 256):
+        # assume IPv4  ('127' gets interpreted as '127.0.0.0')
+        bytes = ipstr.split('.')
+        if len(bytes) > 4:
+            raise ValueError, "IPv4 Address with more than 4 bytes"
+        bytes += ['0'] * (4 - len(bytes))
+        bytes = [long(x) for x in bytes]
+        for x in bytes:
+            if x > 255 or x < 0:
+                raise ValueError, "%r: single byte must be 0 <= byte < 256" % (ipstr)
+        return ((bytes[0] << 24) + (bytes[1] << 16) + (bytes[2] << 8) + bytes[3], 4)
+
+    else:
+        # we try to interprete it as a decimal digit -
+        # this ony works for numbers > 255 ... others
+        # will be interpreted as IPv4 first byte
+        ret = long(ipstr)
+        if ret > 0xffffffffffffffffffffffffffffffffL:
+            raise ValueError, "IP Address cant be bigger than 2^128"
+        if ret <= 0xffffffff:
+            return (ret, 4)
+        else:
+            return (ret, 6)
+
+
+def intToIp(ip, version):
+    """Transform an integer string into an IP address."""
+
+    # just to be sure and hoping for Python 2.22
+    ip = long(ip)
+
+    if ip < 0:
+        raise ValueError, "IPs can't be negative: %d" % (ip)
+    
+    ret = ''
+    if version == 4: 
+        if ip > 0xffffffffL:
+            raise ValueError, "IPv4 Addresses can't be larger than 0xffffffff: %s" % (hex(ip))
+        for l in range(4):
+            ret = str(ip & 0xffL) + '.' + ret
+            ip = ip >> 8;
+        ret = ret[:-1]
+    elif version == 6:
+        if ip > 0xffffffffffffffffffffffffffffffffL:
+            raise ValueError, "IPv6 Addresses can't be larger than 0xffffffffffffffffffffffffffffffff: %s" % (hex(ip))
+        l = '0' * 32 + hex(ip)[2:-1]
+        for x in range(1,33):
+            ret = l[-x] + ret
+            if x % 4 == 0:
+                ret = ':' + ret
+        ret = ret[1:]
+    else:
+        raise ValueError, "only IPv4 and IPv6 supported"
+            
+    return ret;
+
+def _ipVersionToLen(version):
+    """Return number of bits in address for a certain IP version.
+
+    >>> _ipVersionToLen(4)
+    32
+    >>> _ipVersionToLen(6)
+    128
+    >>> _ipVersionToLen(5)
+    Traceback (most recent call last):
+      File "<stdin>", line 1, in ?
+      File "IPy.py", line 1076, in _ipVersionToLen
+        raise ValueError, "only IPv4 and IPv6 supported"
+    ValueError: only IPv4 and IPv6 supported
+    """
+
+    if version == 4:
+        return 32
+    elif version == 6:
+        return 128
+    else:
+        raise ValueError, "only IPv4 and IPv6 supported"
+
+
+def _countFollowingZeros(l):
+    """Return Nr. of elements containing 0 at the beginning th the list."""
+    if len(l) == 0:
+        return 0
+    elif l[0] != 0:
+        return 0
+    else:
+        return 1 + _countFollowingZeros(l[1:])
+
+
+_BitTable = {'0': '0000', '1': '0001', '2': '0010', '3': '0011',
+            '4': '0100', '5': '0101', '6': '0110', '7': '0111',
+            '8': '1000', '9': '1001', 'a': '1010', 'b': '1011',
+            'c': '1100', 'd': '1101', 'e': '1110', 'f': '1111'}
+        
+def _intToBin(val):
+    """Return the binary representation of an integer as string."""
+
+    if val < 0:
+        raise ValueError, "Only positive Values allowed"
+    s = hex(val).lower()
+    ret = ''
+    if s[-1] == 'l':
+        s = s[:-1]
+    for x in s[2:]:
+        if __debug__:
+            if not _BitTable.has_key(x):
+                raise AssertionError, "hex() returned strange result"
+        ret += _BitTable[x]
+    # remove leading zeros
+    while ret[0] == '0' and len(ret) > 1:
+        ret = ret[1:]
+    return ret 
+
+def _count1Bits(num):
+    """Find the highest bit set to 1 in an integer."""
+    ret = 0
+    while num > 0:
+        num = num >> 1
+        ret += 1
+    return ret
+
+def _count0Bits(num):
+    """Find the highest bit set to 0 in an integer."""
+
+    # this could be so easy if _count1Bits(~long(num)) would work as excepted
+    num = long(num)
+    if num < 0:
+        raise ValueError, "Only positive Numbers please: %s" % (num)
+    ret = 0
+    while num > 0:
+        if num & 1 == 1:
+            break
+        num = num >> 1
+        ret += 1
+    return ret 
+
+    
+def _checkPrefix(ip, prefixlen, version):
+    """Check the validity of a prefix
+    
+    Checks if the variant part of a prefix only has 0s, and the length is
+    correct.
+
+    >>> _checkPrefix(0x7f000000L, 24, 4)
+    1
+    >>> _checkPrefix(0x7f000001L, 24, 4)
+    0
+    >>> repr(_checkPrefix(0x7f000001L, -1, 4))
+    'None'
+    >>> repr(_checkPrefix(0x7f000001L, 33, 4))
+    'None'
+    """
+
+    # TODO: unify this v4/v6/invalid code in a function
+    bits = _ipVersionToLen(version)
+    
+    if prefixlen < 0 or prefixlen > bits:
+        return None
+
+    if ip == 0: 
+        zbits = bits + 1
+    else:
+        zbits = _count0Bits(ip)
+    if zbits <  bits - prefixlen:
+        return 0
+    else:
+        return 1
+
+
+def _checkNetmask(netmask, masklen):
+    """Checks if a netmask is expressable as e prefixlen."""
+
+    num = long(netmask)
+    bits = masklen
+    
+    # remove zero bits at the end
+    while (num & 1) == 0:
+        num = num >> 1
+        bits -= 1
+        if bits == 0:
+            break
+    # now check if the rest consists only of ones
+    while bits > 0:
+        if (num & 1) == 0:
+            raise ValueError, "Netmask %s can't be expressed as an prefix." % (hex(netmask))
+        num = num >> 1
+        bits -= 1
+
+
+def _checkNetaddrWorksWithPrefixlen(net, prefixlen, version):
+    """Check if a base addess of e network is compatible with a prefixlen"""
+    if net & _prefixlenToNetmask(prefixlen, version) == net:
+        return 1
+    else:
+        return 0
+    
+
+def _netmaskToPrefixlen(netmask):
+    """Convert an Integer reprsenting a Netmask to an prefixlen.
+
+    E.g. 0xffffff00 (255.255.255.0) returns 24
+    """
+
+    netlen = _count0Bits(netmask)
+    masklen = _count1Bits(netmask)
+    _checkNetmask(netmask, masklen)
+    return masklen - netlen
+
+
+def _prefixlenToNetmask(prefixlen, version):
+    """Return a mask of n bits as a long integer.
+
+    From 'IP address conversion functions with the builtin socket module' by Alex Martelli
+    http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/66517
+    """
+    if prefixlen == 0:
+        return 0
+    elif prefixlen < 0:
+        raise ValueError, "Prefixlen must be > 0"
+    return ((2L<<prefixlen-1)-1) << (_ipVersionToLen(version) - prefixlen)
+         
+
+def _test():
+    import doctest, IPy
+    return doctest.testmod(IPy)
+
+if __name__ == "__main__":
+    _test()
+
+    t = [0xf0, 0xf00, 0xff00, 0xffff00, 0xffffff00L]
+    o = []
+    for x in t:
+        pass
+    x = 0L

Added: packages/ipy/branches/upstream/current/example/confbuilder
URL: http://svn.debian.org/wsvn/python-modules/packages/ipy/branches/upstream/current/example/confbuilder?rev=371&op=file
==============================================================================
--- packages/ipy/branches/upstream/current/example/confbuilder (added)
+++ packages/ipy/branches/upstream/current/example/confbuilder Mon May  1 12:03:34 2006
@@ -1,0 +1,169 @@
+use Net::IP;
+
+ at ns=(':ns.nerxs.com',':ns.dorsch.org',':ns.c0re.jp');
+
+print "\n# domains\n";
+
+open(IN, '<domains');
+
+while(<IN>)
+{
+  if(!/^#/)
+     {	
+      s/\n//;
+      ($domain, $owner) = split(/:/);
+      print ("'$domain:Contact for this domain is $owner\n");
+      foreach (@ns) 
+      {
+	print (".".$domain.":$_\n");
+      }
+     }
+   }
+
+
+print "\n# networks\n";
+      
+open(IN, '<networks');
+
+while(<IN>)
+  {
+
+    if(!/^#/)
+       {	
+	s/\n//;
+	print "# $_\n";
+	@nets = split(/,/);
+	$name = shift @nets;
+	foreach(@nets)
+	{
+	  my $ip = new Net::IP($_) or die (Net::IP::Error());
+	  $net=$ip->ip();
+	  $last=$ip->last_ip();
+	  $net =~ s/://g;
+	  $last =~ s/://g;
+	  
+	  if($ip->size() > 32)
+	    {
+	      foreach (@ns) 
+		{
+		  print (".".$ip->reverse_ip().":$_\n");
+		}
+	        $ip6map{$ip->ip()} = $name;
+	    }
+	  else
+	    {
+	      for($i = int($ip->intip()) + 1; $i < int($ip->intip()) + int($ip->size()); $i++)
+		{
+		  $nmap{sprintf("%d.%d.%d.%d", ($i >> 24) & 0xff, ($i >> 16) & 0xff, ($i>>8) & 0xff, $i & 0xff)} = "$name";
+		  $rmap{sprintf("%d.%d.%d.%d", ($i >> 24) & 0xff, ($i >> 16) & 0xff, ($i>>8) & 0xff, $i & 0xff)} = $ip->binip(). ".$name";
+		}
+	    }
+	  print ("=net.$name:".$net."\n");
+	  print ("=broadcast.$name:".$last."\n");
+	  #print ("Bin : ".$ip->binip()."\n");
+	  #print ("Mask: ".$ip->mask()."\n");
+	  #print ("Size: ".$ip->size()."\n");
+	  #print ("Type: ".$ip->iptype()."\n");
+	}
+       }
+     }
+      
+close(IN);
+
+print "\n# hosts\n";
+      
+open(IN, '<hosts');
+
+while(<IN>)
+  {
+    s/\n//;
+    if(!/^#/)
+       {	
+	if(!/^-/)
+	{
+	  if(/^=/ || /^\+/)
+	    {
+	      @i = split(':');
+	      $rmap{$i[1]} = '';
+	    }
+	  print "$_\n";
+	}
+	else
+	{
+	  @fields = split(/\|/);
+	  $name = shift(@fields);
+	  $name =~ s/^.(.)/$1/;
+	  $_ = shift(@fields);
+	  @ips = split(/,/);
+	  $_ = shift(@fields);
+	  @aliases = split(/,/);
+	  $admin = shift(@fields);
+	  if(!$admin)
+	    {
+	      $admin = 'technik at c0re.23.nu';
+ 	    }
+	  $_ = shift(@fields);
+	  @mxes = split(/,/);
+	  foreach(@ips)
+	    {
+	      my $ip = new Net::IP($_) or die (Net::IP::Error());
+	      if(length($ip->binip()) == 32)
+		 {
+		   # IPv4 is easy
+		   if(!$nmap{$_})
+		     {
+		       print STDERR "*** warning: no network for $_ ($name) - ignoring\n";
+		       print "# no network for $_ ($name) - ignoring\n";
+		     }
+		   else  
+		     {
+		       print "=$name." . $nmap{$_} . ":$_\n";
+		       $rmap{$_} = '';      
+		       print "'$name." . $nmap{$_} . ":Host contact is $admin\n";
+		     }	
+		   foreach(@aliases)
+		     {
+		       print "+$_:".$ip->ip()."\n";
+		       print "'$_:Host contact is $admin\n";
+		     }
+		 }
+	      else
+		{
+		  #IPv6 here
+		  $net = $ip->ip();
+		  $net  =~ s/^(....:....:....:....).*/$1:0000:0000:0000:0000/;
+		  if(!$ip6map{$net})
+		    {
+		      print STDERR "*** warning: no network for $_ ($name) - ignoring\n";
+		      print "# no network for $_ ($name) - ignoring\n";
+		    }
+		  else  
+		     {
+		       $rip = $ip->ip();
+		       $rip =~ s/://g;
+		       print "6$name." . $ip6map{$net} . ":".$rip."\n";
+		    }
+	      foreach(@aliases)
+		{
+		  $rip = $ip->ip();
+		  $rip =~ s/://g;
+		  print "3$_:".$rip."\n";      		    
+		}
+		}	
+
+	    }
+	}
+       }
+     }
+      
+close(IN);
+
+
+print "\n# reverse lookup\n";
+foreach(sort(keys(%nmap))) 
+{
+  if($rmap{$_})
+    {
+      print "=".$rmap{$_}.":$_\n";
+    }
+}

Added: packages/ipy/branches/upstream/current/example/confbuilder.py
URL: http://svn.debian.org/wsvn/python-modules/packages/ipy/branches/upstream/current/example/confbuilder.py?rev=371&op=file
==============================================================================
--- packages/ipy/branches/upstream/current/example/confbuilder.py (added)
+++ packages/ipy/branches/upstream/current/example/confbuilder.py Mon May  1 12:03:34 2006
@@ -1,0 +1,141 @@
+# This is a hack I use to generate my tinydns configuration
+# It serves as e test for converting from Perl Net::IP to
+# Python and IPy
+
+# Further Information might be available at http://c0re.jp/c0de/IPy/
+# Hacked 2001 by drt at un.bewaff.net
+
+import sys
+sys.path.append('..')
+
+import IPy
+
+
+ns = {'ns.nerxs.com': '213.221.113.70',
+      'ns.dorsch.org': '195.143.234.25',
+      'ns.c0re.jp': '217.6.214.130'}
+
+print "# *** nameservers ***"
+for x in ns.keys():
+    print "=%s:%s" % (x, ns[x])
+
+print "\n# *** domains ***"
+
+fd = open('domains')
+
+for x in fd.readlines():
+    if x[0] != '#':
+        if x[-1] == '\n':
+            x = x[:-1]
+        (domain, owner) = x.split(':')
+        print "'%s:Contact for this domain is %s" % (domain, owner)
+        for y in ns.keys(): 
+            print ".%s::%s" % (domain, y)
+
+fd.close()
+
+print "\n# *** Networks ***"
+
+fd = open('networks')
+ip6map = {}
+rmap = {}
+nmap = {}
+
+for x in fd.readlines():
+    if x[-1] == '\n':
+        x = x[:-1]
+    if len(x) > 0 and x[0] != '#':
+        nets = x.split(',')
+        name = nets.pop(0)
+        print "# Network: %s" % name
+        for y in nets:
+            ip = IPy.IP(y)
+            print "# Address range: %s (%s), %d addresses" % (ip.strCompressed(), ip.iptype(), ip.len())
+            print "=net.%s:%s" % (name, ip.net())
+            print "=broadcast.%s:%s" % (name, ip.broadcast())
+            
+            if ip.version() == 4:
+                for z in ip:
+                    # TODO reverse?
+                    nmap[z.int()] = name
+                    rmap[z.int()] = z.strBin() + "." + name
+            else:
+                # IPv6
+                for z in ns.keys():
+                    for v in ip.reverseName():
+                        print ".%s::%s" % (v, z) 
+                ip6map[ip.strFullsize(0)] = name
+
+fd.close()
+
+print "\n# *** hosts ***"
+      
+fd = open('hosts')
+
+for x in fd.readlines():
+    if x[-1] == '\n':
+        x = x[:-1]
+    if x != '' and x[0] != '#':
+        if "@Z'.".find(x[0]) >= 0:
+            print x
+        else:
+            if "=+'".find(x[0]) >= 0:
+                i = x.split(':')
+                rmap[IPy.IP(i[1]).int()] = ''
+                print x
+            else:
+                x = x[1:]
+                x += '||||'
+                fields = x.split('|')
+                name = fields.pop(0)
+                if name[0] == '.':
+                    name = name[1:]
+                v = fields.pop(0)
+                ips = v.split(',')
+                v = fields.pop(0)
+                aliases = v.split(',')
+                if aliases == ['']:
+                    aliases = []
+                admin = fields.pop()
+                if admin == '':
+                    admin = 'technik at c0re.23.nu'
+                v = fields.pop()
+                mxes = v.split(',')
+                if mxes == ['']:
+                    mxes = []
+                for y in ips:
+                    ip = IPy.IP(y) 
+                    if ip.version() == 4:
+                        # IPv4 is easy
+                        if not nmap.has_key(ip.int()):
+                            print >>sys.stderr, "*** warning: no network for %s (%s) - ignoring" % (y, name)
+                            print "# no network for %s (%s)" % (y, name)
+                        else:
+                            print "=%s.%s:%s" % (name, nmap[ip.int()], y)
+                            print "'%s.%s:Host contact is %s" % (name, nmap[ip.int()], admin)
+                            rmap[ip.int()] = ''      
+                            for z in aliases:
+                                print "+%s:%s" % (z, ip)
+                                print "'%s:Host contact is %s" % (z, admin)
+                    else:
+                        #IPv6 here
+                        net = ip.strFullsize(0)
+                        net = net[:19] + ':0000:0000:0000:0000'
+                        if ip6map.has_key(net):
+                            print >>sys.stderr, "*** warning: no network for %s (%s) - ignoring" % (ip, name)
+                            print "# no network for %s (%s) - ignoring" % (ip, name)
+                        else:  
+                            print "6%s.%s:%s"; (name, ip6map[net], ip.strHex()[2:])
+                            for z in aliases:
+                                print "3%s:%s" % (name, ip.strHex()[2:])
+                                print "'%s:Host contact is %s" % (name, admin)
+
+fd.close()
+
+print "\n# *** reverse lookup ***"
+k = nmap.keys()
+k.sort()
+for x in k:
+    if rmap.has_key(x) and rmap[x] != '':
+      print "=%s:%s" % (rmap[x], str(IPy.IP(x)))
+

Added: packages/ipy/branches/upstream/current/setup.py
URL: http://svn.debian.org/wsvn/python-modules/packages/ipy/branches/upstream/current/setup.py?rev=371&op=file
==============================================================================
--- packages/ipy/branches/upstream/current/setup.py (added)
+++ packages/ipy/branches/upstream/current/setup.py Mon May  1 12:03:34 2006
@@ -1,0 +1,10 @@
+# $Id: setup.py 671 2004-08-22 21:02:29Z md $
+from distutils.core import setup
+setup(name="IPy",
+      version="0.41",
+      description="IPv4 and IPv6 parsing and handling class",
+      author="drt",
+      author_email="drt at un.bewaff.net",
+      url="http://c0re.jp/c0de/Ipy/",
+      py_modules=["IPy"])
+

Added: packages/ipy/branches/upstream/current/test/test_IPy.py
URL: http://svn.debian.org/wsvn/python-modules/packages/ipy/branches/upstream/current/test/test_IPy.py?rev=371&op=file
==============================================================================
--- packages/ipy/branches/upstream/current/test/test_IPy.py (added)
+++ packages/ipy/branches/upstream/current/test/test_IPy.py Mon May  1 12:03:34 2006
@@ -1,0 +1,771 @@
+"""Unit test for IPy.py
+
+Further Information might be available at http://c0re.jp/c0de/IPy/
+
+Hacked 2001 by drt at un.bewaff.net
+"""
+
+# TODO: unify assert / FilIf usage
+
+import sys
+sys.path.append('..')
+sys.path.append('.')
+
+import IPy
+import unittest
+import random
+
+testloops = 250
+
+class parseAddress(unittest.TestCase):
+    okValues = [('FEDC:BA98:7654:3210:FEDC:BA98:7654:3210', 338770000845734292534325025077361652240L),
+                ('FEDCBA9876543210FEDCBA9876543210', 338770000845734292534325025077361652240L),
+                ('0xFEDCBA9876543210FEDCBA9876543210', 338770000845734292534325025077361652240L),
+                ('1080:0000:0000:0000:0008:0800:200C:417A', 21932261930451111902915077091070067066L),
+                ('1080:0:0:0:8:800:200C:417A', 21932261930451111902915077091070067066L),
+                ('1080:0::8:800:200C:417A', 21932261930451111902915077091070067066L),
+                ('1080::8:800:200C:417A', 21932261930451111902915077091070067066L),
+                ('FF01:0:0:0:0:0:0:43', 338958331222012082418099330867817087043L),
+                ('FF01:0:0::0:0:43', 338958331222012082418099330867817087043L),
+                ('FF01::43', 338958331222012082418099330867817087043L),
+                ('0:0:0:0:0:0:0:1', 1L),
+                ('0:0:0::0:0:1', 1L),
+                ('::1', 1L),
+                ('0:0:0:0:0:0:0:0', 0L),
+                ('0:0:0::0:0:0', 0L),
+                ('::', 0L),
+                ('0:0:0:0:0:0:13.1.68.3', 218186755L),
+                ('::13.1.68.3', 218186755L),
+                ('0:0:0:0:0:FFFF:129.144.52.38', 281472855454758L),
+                ('::FFFF:129.144.52.38', 281472855454758L),
+                ('1080:0:0:0:8:800:200C:417A', 21932261930451111902915077091070067066L),
+                ('1080::8:800:200C:417A', 21932261930451111902915077091070067066L),
+                ('0.0.0.0', 0L),
+                ('0', 0L),
+                ('127.0.0.1', 2130706433L),
+                ('255.255.255.255', 4294967295L),
+                ('0.0.0.1', 1L),
+                ('1', 16777216L),
+                ('213.221.113.87', 3588059479L),
+                ('0000', 0L),
+                ('127001', 127001L),
+                ('1234576', 1234576L),
+                ('1', 16777216L),
+                ('232111387', 232111387L),
+                ('255', 4278190080L),
+                ('256', 256L),
+                ('0xffffffff', 4294967295L),
+                ('0x100000000', 4294967296L),
+                ('0xffffffffffffffffffffffffffffffff', 0xffffffffffffffffffffffffffffffffL),
+                ('0xdeadbeef', 0xdeadbeefL),
+                ('0xdeadbabe', 0xdeadbabeL),
+                ('0xdeadc0de', 0xdeadc0deL),
+                ('0xc0decafe', 0xc0decafeL),
+                ('0xc0debabe', 0xc0debabeL),
+                ('0xbabec0de', 0xbabec0deL),
+                ('0xcafebabe', 0xcafebabeL),
+                ('0x1', 1L),
+                ('0xabcdef', 11259375L)]
+
+    # TODO: check for more invalid input
+
+    def testKnownValues(self):
+        """parsing of known values should give known results"""
+        for x in self.okValues:
+            (question, answer) = x
+            (result, version) = IPy.parseAddress(question)
+            self.assertEqual(answer, result, "%r, %r, %r" % (question, answer, result))
+
+    def testVersionDistinction(self):
+        """problems destinguishing IPv4 and IPv6"""
+        (result, version) = IPy.parseAddress('0xffffffff')
+        self.assertEqual(version, 4)
+        (result, version) = IPy.parseAddress('0x100000000')
+        self.assertEqual(version, 6)
+            
+    def testEmpty(self):
+        """'' should raise an exception"""
+        self.assertRaises(ValueError, IPy.parseAddress, '')
+
+    def testTooBig(self):
+        """'' should raise an exception"""
+        self.assertRaises(ValueError, IPy.parseAddress, '0x100000000000000000000000000000000')
+
+    def testLongIPv4(self):
+        """'1.2.3.4.5' should raise an exception"""
+        self.assertRaises(ValueError, IPy.parseAddress, '1.2.3.4.5')
+
+    def testNonByteIPv4(self):
+        """'1.2.3.256' should raise an exception"""
+        self.assertRaises(ValueError, IPy.parseAddress, '1.2.3.256')
+
+    def testNegativeByteIPv4(self):
+        """'-1.2.3.4' and '1.2.3.-4' should raise an exception"""
+        self.assertRaises(ValueError, IPy.parseAddress, '-1.2.3.4')
+        self.assertRaises(ValueError, IPy.parseAddress, '1.2.3.-4')
+
+    def testTripleColonIPv6(self):
+        """'2001:::1' should raise an exception"""
+        self.assertRaises(ValueError, IPy.parseAddress, '2001:::1')
+
+    def testRepeatDoubleColonIPv6(self):
+        """'2001::ABCD::1' should raise an exception"""
+        self.assertRaises(ValueError, IPy.parseAddress, '2001::ABCD::1')
+
+    def testDoubleColonWithEightHextetsIPv6(self):
+        """'1111::2222:3333:4444:5555:6666:7777:8888' should raise an exception"""
+        self.assertRaises(ValueError, IPy.parseAddress, '1111::2222:3333:4444:5555:6666:7777:8888')
+
+    def testBeginningColonWithEightHextetsIPv6(self):
+        """':1111:2222:3333:4444:5555:6666:7777:8888' should raise an exception"""
+        self.assertRaises(ValueError, IPy.parseAddress, ':1111:2222:3333:4444:5555:6666:7777:8888')
+
+    def testEndingColonWithEightHextetsIPv6(self):
+        """'1111:2222:3333:4444:5555:6666:7777:8888:' should raise an exception"""
+        self.assertRaises(ValueError, IPy.parseAddress, '1111:2222:3333:4444:5555:6666:7777:8888:')
+
+    def testNegativeHexletIPv6(self):
+        """'2001:-ABCD::1' should raise an exception"""
+        self.assertRaises(ValueError, IPy.parseAddress, '2001:-ABCD::1')
+
+    def testTooBigHexletIPv6(self):
+        """'2001:10000::1' should raise an exception"""
+        self.assertRaises(ValueError, IPy.parseAddress, '2001:10000::1')
+
+    def testShortAddressIPv6(self):
+        """'1111:2222:3333:4444:5555:6666:7777' should raise an exception"""
+        self.assertRaises(ValueError, IPy.parseAddress, '1111:2222:3333:4444:5555:6666:7777')
+
+    def testLongAddressIPv6(self):
+        """'1111:2222:3333:4444:5555:6666:7777:8888:9999' should raise an exception"""
+        self.assertRaises(ValueError, IPy.parseAddress, '1111:2222:3333:4444:5555:6666:7777:8888:9999')
+
+class _intToIP(unittest.TestCase):
+    v4values = [(0x7f000001, '127.0.0.1'),
+                (0x0, '0.0.0.0'),
+                (0x1, '0.0.0.1'),
+                (0xf, '0.0.0.15'),
+                (0xff, '0.0.0.255'),
+                (0xFFFFFFFFL, '255.255.255.255')]
+    v6values = [(0x7f000001, '0000:0000:0000:0000:0000:0000:7F00:0001'),
+                (0x0, '0000:0000:0000:0000:0000:0000:0000:0000'),
+                (0x1, '0000:0000:0000:0000:0000:0000:0000:0001'),
+                (0xf, '0000:0000:0000:0000:0000:0000:0000:000F'),
+                (0xff, '0000:0000:0000:0000:0000:0000:0000:00FF'),
+                (0xFFFFFFFFL, '0000:0000:0000:0000:0000:0000:FFFF:FFFF'),
+                (0x100000000L, '0000:0000:0000:0000:0000:0001:0000:0000'),
+                (0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFL, 'FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF')]
+
+    def testKnownValuesv4(self):
+        """printing of known IPv4 values should give known results"""
+        for x in self.v4values:
+            (question, answer) = x
+            result  = IPy.intToIp(question, 4)
+            self.assertEqual(answer, result, "%r, %r, %r" % (question, answer, result))
+
+    def testKnownValuesv6(self):
+        """printing of known IPv6 values should give known results"""
+        for x in self.v6values:
+            (question, answer) = x
+            result  = IPy.intToIp(question, 6)
+            self.assertEqual(answer, result, "%r, %r, %r" % (question, answer, result))
+ 
+    def testNegativeIPv4(self):
+        """negative IPv4 Values should raise an exception"""
+        self.assertRaises(ValueError, IPy.intToIp, -1, 4)
+
+    def testNegativeIPv6(self):
+        """negative IPv6 Values should raise an exception"""
+        self.assertRaises(ValueError, IPy.intToIp, -1, 6)
+
+    def testLargeIPv4(self):
+        """IPv4: Values > 0xffffffff should raise an exception"""
+        self.assertRaises(ValueError, IPy.intToIp, 0x100000000L, 4)
+
+    def testLargeIPv6(self):
+        """IPv6: Values > 0xffffffffffffffffffffffffffffffff should raise an exception"""
+        self.assertRaises(ValueError, IPy.intToIp, 0x100000000000000000000000000000000L, 6)
+
+    def testIllegalVersion(self):
+        """IPVersion other than 4 and 6 should raise an exception"""
+        self.assertRaises(ValueError, IPy.intToIp, 1, 0)
+        self.assertRaises(ValueError, IPy.intToIp, 1, 1)
+        self.assertRaises(ValueError, IPy.intToIp, 1, 2)
+        self.assertRaises(ValueError, IPy.intToIp, 1, 3)
+        self.assertRaises(ValueError, IPy.intToIp, 1, 5)
+        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 = long(random.randrange(0x7fffffff)) + long(random.randrange(0x7fffffff))
+            self.assertEqual(IPy.parseAddress(IPy.intToIp(question, 4)), (question, 4), hex(question))
+
+    def testRandomValuesv6(self):
+        for i in range(testloops):
+            question = ((long(random.randrange(0x7fffffff)) + long(random.randrange(0x7fffffff))) +
+                        ((long(random.randrange(0x7fffffff)) + long(random.randrange(0x7fffffff))) << 32) +
+                        ((long(random.randrange(0x7fffffff)) + long(random.randrange(0x7fffffff))) << 64) +
+                        ((long(random.randrange(0x7fffffff)) + long(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)
+        self.assertEqual(IPy._count1Bits(0xf), 4)
+        self.assertEqual(IPy._count1Bits(0x10), 5)
+        self.assertEqual(IPy._count1Bits(0xff), 8)
+        self.assertEqual(IPy._count1Bits(0xffff), 16)
+        self.assertEqual(IPy._count1Bits(0xffffffffL), 32)
+        self.assertEqual(IPy._count1Bits(0xffffffffffffffffffffffffffffffffL), 128)
+
+    def testCount1Bits(self):
+        self.assertEqual(IPy._count0Bits(0), 0)
+        self.assertEqual(IPy._count0Bits(0xf0L), 4)
+        self.assertEqual(IPy._count0Bits(0xf00L), 8)
+        self.assertEqual(IPy._count0Bits(0xf000L), 12)
+        self.assertEqual(IPy._count0Bits(0xf0000L), 16)
+        self.assertEqual(IPy._count0Bits(0xf00000L), 20)
+        self.assertEqual(IPy._count0Bits(0xf000000L), 24)
+        self.assertEqual(IPy._count0Bits(0xf0000000L), 28)
+        self.assertEqual(IPy._count0Bits(0xff000000L), 24)
+        self.assertEqual(IPy._count0Bits(0xfff00000L), 20)
+        self.assertEqual(IPy._count0Bits(0x80000000L), 31)
+        self.assertEqual(IPy._count0Bits(0xf0000000000000000000000000000000L), 124)
+        self.assertEqual(IPy._count0Bits(0x80000000000000000000000000000000L), 127)
+        
+       
+class _intToBin(unittest.TestCase):
+    knownValues = [(0, '0'), (1, '1'), (2, '10'), (3, '11'), (4, '100'), (5, '101'),
+                   (6, '110'), (7, '111'), (8, '1000'), (9, '1001'),
+                   (0xf, '1111'), (0xff, '11111111'),
+                   (0xFFFFFFFFL, '11111111111111111111111111111111'),
+                   (0x100000000L, '100000000000000000000000000000000'),
+                   (0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFL, '11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111'),
+                   (0x100000000000000000000000000000000L, '100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000')]
+
+    def testKnownValues(self):
+        """conversion of known values values should give known results"""
+        for x in self.knownValues:
+            (question, answer) = x
+            result  = IPy._intToBin(question)
+            self.assertEqual(answer, result, str(question))
+
+    def testNegativeIPv4(self):
+        """negative Values should raise an exception"""
+        self.assertRaises(ValueError, IPy._intToBin, -1)
+
+class netmaskPrefixlenConv(unittest.TestCase):
+    known4Values = [(0xFFFFFFFFL, 32), (0xFFFFFFFEL, 31), (0xFFFFFFFCL, 30), (0xFFFFFFF8L, 29),
+                    (0xFFFFFFF0L, 28), (0xFFFFFFE0L, 27), (0xFFFFFFC0L, 26), (0xFFFFFF80L, 25),
+                    (0xFFFFFF00L, 24), (0xFFFFFE00L, 23), (0xFFFFFC00L, 22), (0xFFFFF800L, 21),
+                    (0xFFFFF000L, 20), (0xFFFFE000L, 19), (0xFFFFC000L, 18), (0xFFFF8000L, 17),
+                    (0xFFFF0000L, 16), (0xFFFE0000L, 15), (0xFFFC0000L, 14), (0xFFF80000L, 13),
+                    (0xFFF00000L, 12), (0xFFE00000L, 11), (0xFFC00000L, 10), (0xFF800000L, 9),
+                    (0xFF000000L, 8), (0xFE000000L, 7), (0xFC000000L, 6), (0xF8000000L, 5),
+                    (0xF0000000L, 4), (0xE0000000L, 3), (0xC0000000L, 2), (0x80000000L, 1)]
+    known6Values = [(0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFL, 128),
+                    (0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEL, 127),
+                    (0xFFFFFFFFFFFFFFFFFFFFFFFF80000000L, 97),
+                    (0xFFFFFFFFFFFFFFFFFFFFFFFF00000000L, 96),
+                    (0xFFFFFFFFFFFFFFFFFFFFFFFE00000000L, 95),
+                    (0xFFFFFFFFFFFFFFFF8000000000000000L, 65),
+                    (0xFFFFFFFFFFFFFFFF0000000000000000L, 64),
+                    (0xFFFFFFFFFFFFFFFE0000000000000000L, 63),
+                    (0xFFFFFFFF800000000000000000000000L, 33),
+                    (0xFFFFFFFF000000000000000000000000L, 32),
+                    (0xFFFFFFFE000000000000000000000000L, 31),
+                    (0xC0000000000000000000000000000000L, 2),
+                    (0x80000000000000000000000000000000L, 1)]
+    
+    def testKnownValuesv4n2p(self):
+        """conversion of known values values should give known results"""
+        for x in self.known4Values:
+            (question, answer) = x
+            result  = IPy._netmaskToPrefixlen(question)
+            self.assertEqual(answer, result, hex(question))
+
+    def testKnownValuesv6n2p(self):
+        """conversion of known values values should give known results"""
+        for x in self.known6Values:
+            (question, answer) = x
+            result  = IPy._netmaskToPrefixlen(question)
+            self.assertEqual(answer, result, hex(question))
+
+    def testKnownValuesv4p2n(self):
+        """conversion of known values values should give known results"""
+        for x in self.known4Values:
+            (answer, question) = x
+            result  = IPy._prefixlenToNetmask(question, 4)
+            self.assertEqual(answer, result, hex(question))
+
+    def testKnownValuesv6p2n(self):
+        """conversion of known values values should give known results"""
+        for x in self.known6Values:
+            (answer, question) = x
+            result  = IPy._prefixlenToNetmask(question, 6)
+            self.assertEqual(answer, result, "%d: %s != %s" % (question, hex(answer), result))
+
+    def testInvalidv4n2p(self):
+        """Netmasks should be all ones in the first part and all zeros in the second part"""
+        self.failUnlessRaises(ValueError, IPy._netmaskToPrefixlen, 0xff00ff00L)
+
+    def testInvalidv6n2p(self):
+        """Netmasks should be all ones in the first part and all zeros in the second part"""
+        self.failUnlessRaises(ValueError, IPy._netmaskToPrefixlen, 0xff00ff00ff00ff00ff00ff00ff00ff00L)
+
+
+class checkChecks(unittest.TestCase):
+
+    def testCheckNetmaskOk(self):
+        """Legal Netmasks should be allowed."""
+        self.failIf(IPy._checkNetmask(0xffffffffL, 32))
+        self.failIf(IPy._checkNetmask(0xffffff00L, 32))
+        self.failIf(IPy._checkNetmask(0xffff0000L, 32))
+        self.failIf(IPy._checkNetmask(0xff000000L, 32))
+        self.failIf(IPy._checkNetmask(0, 32))
+
+    def testCheckNetmaskFail(self):
+        """Illegal Netmasks should be rejected."""
+        self.failUnlessRaises(ValueError, IPy._checkNetmask, 0xf0ffffffL, 32)
+        self.failUnlessRaises(ValueError, IPy._checkNetmask, 0xf0f0f0f0L, 32)
+        self.failUnlessRaises(ValueError, IPy._checkNetmask, 0xff00ff00L, 32)
+        self.failUnlessRaises(ValueError, IPy._checkNetmask, 0x70000001L, 32)
+        self.failUnlessRaises(ValueError, IPy._checkNetmask, 0xfffffffL, 32)
+
+    def testCheckPrefixOk(self):
+        """Legal IP/prefix combinations should check ok."""
+        self.failUnless(IPy._checkPrefix(0x0, 32, 4))
+        self.failUnless(IPy._checkPrefix(0xffffffffL, 32, 4))
+        self.failUnless(IPy._checkPrefix(0x7f000001L, 32, 4))
+        self.failUnless(IPy._checkPrefix(0x80000000L, 1, 4))
+        self.failUnless(IPy._checkPrefix(0x40000000L, 2, 4))
+        self.failUnless(IPy._checkPrefix(0x80000000L, 3, 4))
+        self.failUnless(IPy._checkPrefix(0x80000000L, 4, 4))
+        self.failUnless(IPy._checkPrefix(0xffffff00L, 24, 4))
+        self.failUnless(IPy._checkPrefix(0xffffff00L, 24, 4))
+        self.failUnless(IPy._checkPrefix(0xfffffff0L, 28, 4))
+        self.failUnless(IPy._checkPrefix(0x0, 32, 4))
+        self.failUnless(IPy._checkPrefix(0x0, 1, 4))
+        self.failUnless(IPy._checkPrefix(0x0, 0, 4))
+        self.failUnless(IPy._checkPrefix(0xffffffffffffffff0000000000000000L, 64, 6))
+        self.failUnless(IPy._checkPrefix(0x0L, 64, 6))
+        self.failUnless(IPy._checkPrefix(0x0L, 0, 6))
+        self.failUnless(IPy._checkPrefix(0x0L, 128, 6))
+        self.failUnless(IPy._checkPrefix(0xffffffffffffffffffffffffffffffffL, 128, 6))
+
+
+    def testCheckPrefixFail(self):
+        """Illegal Prefixes should be catched."""
+        self.failIf(IPy._checkPrefix(0x7f000001L, -1, 4))
+        self.failIf(IPy._checkPrefix(0x7f000001L, 33, 4))
+        self.failIf(IPy._checkPrefix(0x7f000001L, 24, 4))
+        self.failIf(IPy._checkPrefix(0x7f000001L, 31, 4))
+        self.failIf(IPy._checkPrefix(0x7f000080L, 24, 4))
+        self.failIf(IPy._checkPrefix(0x7f000100L, 23, 4))
+        self.failIf(IPy._checkPrefix(0x7f000000L, 1, 4))
+        self.failIf(IPy._checkPrefix(0x7f000000L, 0, 4))
+        self.failIf(IPy._checkPrefix(0x1L, -1, 6))
+        self.failIf(IPy._checkPrefix(0x1L, 129, 6))
+        self.failIf(IPy._checkPrefix(0xffffffffffffffff0000000000000001L, 64, 6))
+        self.failIf(IPy._checkPrefix(0xffffffffffffffff1000000000000000L, 64, 6))
+    
+
+    # TODO: _checkNetaddrWorksWithPrefixlen(net, prefixlen, version):
+    
+class PythonObjectBehaviour(unittest.TestCase):
+    def testIfUsuableAsDictionaryKey(self):
+        """IP Object should be usable as dictionary key"""
+        d = {}
+        d[IPy.IP('127.0.0.1')] = 1
+        d[IPy.IP('2001::1')] = 1
+        d[IPy.IP('127.0.0.0/24')] = 1
+        d[IPy.IP('2001::/64')] = 1
+
+    def testIfCanBeInteratedOver(self):
+        """It should be possible to iterate over an IP Object."""
+        i = 0
+        for x in IPy.IP('127.0.0.0/24'):
+            i += 1
+        self.assertEqual(i, 256, "iteration over a /24 should yiels 256 values")
+        i = 0
+        for x in IPy.IP('2001::/124'):
+            i += 1
+        self.assertEqual(i, 16, "iteration over a /124 should yiels 16 values")
+
+    def testIfComparesEqual(self):
+        """nets of the same base and size should be considered equal, others not"""
+        a = IPy.IP('127.0.0.0/24')
+        a2 = a
+        b = IPy.IP('127.0.0.0/24')
+        c = IPy.IP('127.0.0.0/23')
+        d = IPy.IP('127.0.0.0/22')
+        e = IPy.IP('64.0.0.0/24')
+        self.assertEqual(a2, a)
+        self.assertEqual(a2, b)
+        self.assertEqual(a, a)
+        self.assertEqual(a, b)
+        self.assertNotEqual(a, c)
+        self.assertNotEqual(a, d)
+        self.assertNotEqual(a, e)
+        self.assertNotEqual(b, c)
+        self.assertNotEqual(b, d)
+        self.assertNotEqual(b, e)
+        self.assertNotEqual(c, d)
+        self.assertNotEqual(c, e)
+        self.assertNotEqual(d, e)
+
+    def testIfContainsInt(self):
+        """__contains__() should work somewhat with ints"""
+        ip = IPy.IP('127.0.0.0/28')
+        for x in ip:
+            self.failUnless(x.int() in ip)
+        ip = IPy.IP('2001::/124')
+        for x in ip:
+            self.failUnless(x.int() in ip)
+
+    def testIfContainsStr(self):
+        """__contains__() should work somewhat with strings"""
+        ip = IPy.IP('127.0.0.0/28')
+        for x in ip:
+            self.failUnless(x.strNormal() in ip, "%r not in %r" % (x.strNormal(), ip))
+        ip = IPy.IP('2001::/124')
+        for x in ip:
+            self.failUnless(x.strNormal() in ip, "%r not in %r" % (x.strNormal(), ip))
+ 
+    def testIfContainsIPobj(self):
+        """__contains__() should work somewhat with IP instances"""
+        ip = IPy.IP('127.0.0.0/28')
+        for x in ip:
+            self.failUnless(x in ip)
+        ip = IPy.IP('2001::/124')
+        for x in ip:
+            self.failUnless(x in ip)
+
+    def testActingAsArray(self):
+        """An IP-object should handle indices."""
+        ip = IPy.IP('127.0.0.0/24')
+        self.assertEqual(ip[0], ip.net())
+        self.assertEqual(ip[-1], ip.broadcast())
+        self.failUnless(ip[255])
+        self.failUnlessRaises(IndexError, ip.__getitem__, 256)
+        
+    def testStr(self):
+        """string() should work somewhat with IP instances"""
+        ip = IPy.IP('127.0.0.0/28')
+        for x in ip:
+            self.failUnless(str(x))
+        ip = IPy.IP('2001::/124')
+        for x in ip:
+            self.failUnless(str(x))
+
+    def testRepr(self):
+        """repr() should work somewhat with IP instances"""
+        ip = IPy.IP('127.0.0.0/28')
+        for x in ip:
+            self.failUnless(repr(x))
+        ip = IPy.IP('2001::/124')
+        for x in ip:
+            self.failUnless(repr(x))
+
+    def testLen(self):
+        """object should have an working __len__() interface."""
+        self.failUnlessEqual(len(IPy.IP('127.0.0.0/28')), 16)
+        self.failUnlessEqual(len(IPy.IP('127.0.0.0/30')), 4)
+        self.failUnlessEqual(len(IPy.IP('127.0.0.0/26')), 64)
+        self.failUnlessEqual(len(IPy.IP('127.0.0.0/16')), 2**16)
+        
+    # cmp
+    # IP[0xffffffff]
+    # IP + IP
+    # reverse
+    # netmsk
+    # ip
+
+class IPobject(unittest.TestCase):
+    def testStrCompressed(self):
+        """Compressed string Output."""
+        testValues = ['127.0.0.1',
+                  'dead::beef',
+                  'dead:beef::',
+                  'dead:beef::/48',
+                  'ff00:1::',
+                  'ff00:0:f000::',
+                  '0:0:1000::',
+                  '::e000:0/112',
+                  '::e001:0/112',
+                  'dead:beef::/48',
+                  'ff00:1::/64',
+                  'ff00:0:f000::/64',
+                  '0:0:1000::/64',
+                  '::e000:0/112',
+                  '::e001:0/112',
+                  '::1:0:0:0:2',
+                  '0:1:2:3:4:5:6:7',
+                  '1:2:3:4:0:5:6:7',
+                  '1:2:3:4:5:6:7:0',
+                  '1:0:0:2::',
+                  '1:0:0:2::3',
+                  '1::2:0:0:3']
+        for question in testValues:
+            result = IPy.IP(question).strCompressed() 
+            self.failUnlessEqual(question, result, (question, result))
+
+    def testStrBin(self):
+        """Binary string Output."""
+
+        testValues = [('0.0.0.0', '00000000000000000000000000000000'),
+                      ('0.0.0.1', '00000000000000000000000000000001'),
+                      ('255.255.255.255', '11111111111111111111111111111111'),
+                      ('128.0.0.0', '10000000000000000000000000000000'),
+                      ('::0', '00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'),
+                      ('::1', '00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001'),
+                      ('ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff', '11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111'),
+                      ('5555:5555:5555:5555:5555:5555:5555:5555', '01010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101'),
+                      ('aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa', '10101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010'),
+                      ('85.85.85.85', '01010101010101010101010101010101'),
+                      ('170.170.170.170', '10101010101010101010101010101010'),
+                      ('127.0.0.1', '01111111000000000000000000000001'),
+                      ('1::2:0:0:3', '00000000000000010000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000011')]
+        for (question, answer) in testValues:
+            result = IPy.IP(question).strBin() 
+            self.failUnlessEqual(answer, result, (question, answer, result))
+
+    def testStrNormal(self):
+        """Normal string Output."""
+        testValues = [(338770000845734292534325025077361652240L, 'fedc:ba98:7654:3210:fedc:ba98:7654:3210'),
+                      (21932261930451111902915077091070067066L, '1080:0:0:0:8:800:200c:417a'),
+                      (338958331222012082418099330867817087043L, 'ff01:0:0:0:0:0:0:43'),
+                      (0L, '0.0.0.0'),
+                      (2130706433L, '127.0.0.1'),
+                      (4294967295L, '255.255.255.255'),
+                      (1L, '0.0.0.1'),
+                      (3588059479L, '213.221.113.87')]
+        for (question, answer) in testValues:
+            result = IPy.IP(question).strNormal(question) 
+            self.failUnlessEqual(answer, result, (question, result, answer))
+
+    def testStrFullsize(self):
+        """Normal / 0-padded string Output."""
+        testValues = [(338770000845734292534325025077361652240L, 'fedc:ba98:7654:3210:fedc:ba98:7654:3210'),
+                      (21932261930451111902915077091070067066L, '1080:0000:0000:0000:0008:0800:200c:417a'),
+                      (338958331222012082418099330867817087043L, 'ff01:0000:0000:0000:0000:0000:0000:0043'),
+                      (0L, '0.0.0.0'),
+                      (2130706433L, '127.0.0.1'),
+                      (4294967295L, '255.255.255.255'),
+                      (1L, '0.0.0.1'),
+                      (3588059479L, '213.221.113.87')]
+        for (question, answer) in testValues:
+            result = IPy.IP(question).strFullsize(question) 
+            self.failUnlessEqual(answer, result, (question, result, answer))
+
+    def testStrHex(self):
+        """Hex string Output."""
+        testValues = [(338770000845734292534325025077361652240L, '0xFEDCBA9876543210FEDCBA9876543210'),
+                      (21932261930451111902915077091070067066L, '0x108000000000000000080800200C417A'),
+                      (338958331222012082418099330867817087043L, '0xFF010000000000000000000000000043'),
+                      (0L, '0x0'),
+                      (1L, '0x1'),
+                      (4294967295l, '0xFFFFFFFF'),
+                      (3588059479L, '0xD5DD7157'),
+                      (0x12345678, '0x12345678')]
+        for (question, answer) in testValues:
+            result = IPy.IP(question).strHex(question) 
+            self.failUnlessEqual(answer, result, (question, result, answer))
+
+    def testStrDec(self):
+        """Decimal string Output."""
+        testValues = [(338770000845734292534325025077361652240L, '338770000845734292534325025077361652240'),
+                      (21932261930451111902915077091070067066L, '21932261930451111902915077091070067066'),
+                      (338958331222012082418099330867817087043L, '338958331222012082418099330867817087043'),
+                      (0L, '0'),
+                      (1L, '1'),
+                      (0xFFFFFFFFL, '4294967295'),
+                      (0xD5DD7157L, '3588059479')]
+        for (question, answer) in testValues:
+            result = IPy.IP(question).strDec(question) 
+            self.failUnlessEqual(answer, result, (question, result, answer))
+
+    def testNet(self):
+        """Returning of the Network Address"""
+        self.failUnlessEqual(str(IPy.IP("127.0.0.1").net()), "127.0.0.1")
+        self.failUnlessEqual(str(IPy.IP("0.0.0.0/0").net()), "0.0.0.0")
+        self.failUnlessEqual(str(IPy.IP("2001:1234:5678:1234::/64").net()), "2001:1234:5678:1234:0000:0000:0000:0000")
+
+        
+    def testBroadcast(self):
+        """Returning of broadcast address."""
+        self.failUnlessEqual(str(IPy.IP("127.0.0.1").broadcast()), "127.0.0.1")
+        self.failUnlessEqual(str(IPy.IP("0.0.0.0/0").broadcast()), "255.255.255.255")
+        self.failUnlessEqual(str(IPy.IP("2001:1234:5678:1234::/64").broadcast()), "2001:1234:5678:1234:ffff:ffff:ffff:ffff")
+
+
+    def testStrNetmask(self):
+        """StrNetmask should return netmasks"""
+        self.failUnlessEqual(IPy.IP("0.0.0.0/0").strNetmask(), "0.0.0.0")
+        self.failUnlessEqual(IPy.IP("0.0.0.0/32").strNetmask(), "255.255.255.255")
+        self.failUnlessEqual(IPy.IP("127.0.0.0/24").strNetmask(), "255.255.255.0")
+        self.failUnlessEqual(IPy.IP("2001:1234:5678:1234::/64").strNetmask(), "/64")
+
+
+    def testNetmask(self):
+        """Netmask should return netmasks"""
+        self.failUnlessEqual(str(IPy.IP("0.0.0.0/0").netmask()), "0.0.0.0")
+        self.failUnlessEqual(str(IPy.IP("0.0.0.0/32").netmask()), "255.255.255.255")
+        self.failUnlessEqual(str(IPy.IP("127.0.0.0/24").netmask()), "255.255.255.0")
+        self.failUnlessEqual(str(IPy.IP("2001:1234:5678:1234::/64").netmask()), "ffff:ffff:ffff:ffff:0000:0000:0000:0000")
+
+    def testInt(self):
+        """Prefixlen"""
+        self.failUnlessEqual(IPy.IP("127.0.0.1").int(), 2130706433)
+        self.failUnlessEqual(IPy.IP("0.0.0.0").int(), 0)
+        self.failUnlessEqual(IPy.IP("255.255.255.255").int(), 0xffffffffL)
+        self.failUnlessEqual(IPy.IP("0000:0000:0000:0000:0000:0000:0000:0000").int(), 0)
+        self.failUnlessEqual(IPy.IP("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff").int(), 0xffffffffffffffffffffffffffffffffL)
+        self.failUnlessEqual(IPy.IP("2001:1234:5678:9abc:de00:0000:0000:0000").int(), 42540857391974671903776007410583339008L)
+    
+
+    def testPrefixlen(self):
+        """Prefixlen"""
+        self.failUnlessEqual(IPy.IP("127.0.0.1").prefixlen(), 32)
+        self.failUnlessEqual(IPy.IP("::1").prefixlen(), 128)
+        self.failUnlessEqual(IPy.IP("10.0.0.0/24").prefixlen(), 24)
+        self.failUnlessEqual(IPy.IP("10.0.0.0-10.0.0.255").prefixlen(), 24)
+        self.failUnlessEqual(IPy.IP("10.0.0.0/255.255.255.0").prefixlen(), 24)
+        self.failUnlessEqual(IPy.IP("2001::/64").prefixlen(), 64)
+
+    
+    def testVersion(self):
+        """IP-version detection should work"""
+        self.failUnlessEqual(IPy.IP("0.0.0.0/0").version(), 4)
+        self.failUnlessEqual(IPy.IP("::1").version(), 6)
+
+    # TODO:
+    #def reverseNames(self):
+    #def reverseName(self):
+    #def __cmp__(self, other):
+    #def __add__(self, other):
+    #def _printPrefix(self, want):
+
+    def testOverlaps(self):
+        """Overlapping Address Ranges."""
+        testValues = [('192.168.0.0/23', '192.168.1.0/24', 1),
+                      ('192.168.0.0/23', '192.168.0.0/20', 1),
+                      ('192.168.0.0/23', '192.168.2.0', 0),
+                      ('192.168.0.0/23', '192.167.255.255', 0),
+                      ('192.168.0.0/23', '192.168.0.0', 1),
+                      ('192.168.0.0/23', '192.168.1.255', 1),
+                      ('192.168.1.0/24', '192.168.0.0/23', -1),
+                      ('127.0.0.1', '127.0.0.1', 1),
+                      ('127.0.0.1', '127.0.0.2', 0)]
+        for (a, b, answer) in testValues:
+            result = IPy.IP(a).overlaps(b) 
+            self.failUnlessEqual(answer, result, (a, b, result, answer))
+
+    def testNetmask(self):
+        """Normal string Output."""
+        testValues = [(338770000845734292534325025077361652240L, '0xFEDCBA9876543210FEDCBA9876543210'),
+                      (21932261930451111902915077091070067066L, '0x108000000000000000080800200C417A'),
+                      (338958331222012082418099330867817087043L, '0xFF010000000000000000000000000043'),
+                      (0L, '0x0'),
+                      (1L, '0x1'),
+                      (4294967295l, '0xFFFFFFFF'),
+                      (3588059479L, '0xD5DD7157')]
+        for (question, answer) in testValues:
+            result = IPy.IP(question).strHex(question) 
+            self.failUnlessEqual(answer, result, (question, result, answer))
+
+# TODO
+#eval(repr(IPy)) 
+# differences between IP and IPint
+
+
+# I ported this checks to be sure that I don't have errors in my own checks.
+class NetIPChecks(unittest.TestCase):
+    """Checks taken from perls Net::IP"""
+    def testMisc(self):
+        ip = IPy.IP('195.114.80/24')
+        self.assertEqual(ip.int(), 3279048704L)
+        self.assertEqual(ip.reverseName(),'80.114.195.in-addr.arpa.')
+        self.assertEqual(ip.strBin(),'11000011011100100101000000000000')
+        self.assertEqual(str(ip.net()),'195.114.80.0')
+        self.assertEqual(str(ip),'195.114.80.0/24')
+        self.assertEqual(ip.prefixlen(),24)
+        self.assertEqual(ip.version(),4)
+        self.assertEqual(ip.len(),256)
+        self.assertEqual(IPy._intToBin(ip.netmask().int()),'11111111111111111111111100000000')
+        self.assertEqual(ip.strNetmask(),'255.255.255.0')
+        self.assertEqual(ip.iptype(), 'PUBLIC')
+        self.assertEqual(ip.broadcast().strBin(),'11000011011100100101000011111111')
+        self.assertEqual(str(ip.broadcast()),'195.114.80.255')
+
+        ip = IPy.IP('202.31.4/24')
+        self.assertEqual(str(ip.net()),'202.31.4.0')
+        
+        self.failUnlessRaises(ValueError, IPy.IP, '234.245.252.253/2')        
+
+        # because we ar using integer representation we don't need a special "binadd"
+        ip = IPy.IP('62.33.41.9')
+        ip2 = IPy.IP('0.1.0.5')
+        self.assertEqual(str(IPy.IP(ip.int() + ip2.int())),'62.34.41.14')
+        #$T->ok_eq ($ip->binadd($ip2)->ip(),'62.34.41.14',$ip->error());
+        
+        ip = IPy.IP('133.45.0/24')
+        ip2 = IPy.IP('133.45.1/24')
+        self.assertEqual((ip + ip2).prefixlen(),23)
+        
+        ip2 = IPy.IP('133.44.255.255');
+        #$T->ok_eqnum ($ip->bincomp('gt',$ip2),1,$ip->error());
+
+        # this is something we can't do with IPy
+        #ip = IPy.IP('133.44.255.255-133.45.0.42');
+        #$T->ok_eq (($ip->find_prefixes())[3],'133.45.0.40/31',$ip->error());
+        
+        ip = IPy.IP('201.33.128.0/22');
+        ip2 = IPy.IP('201.33.129.0/24');
+        #$T->ok_eqnum ($ip->overlaps($ip2),$IP_B_IN_A_OVERLAP,$ip->error());
+        
+        ip = IPy.IP('dead:beef:0::/48')
+        self.assertEqual(str(ip.net()),'dead:beef:0000:0000:0000:0000:0000:0000')
+        self.assertEqual(ip.int(), 295990755014133383690938178081940045824L)
+        self.assertEqual(ip.strBin(),'11011110101011011011111011101111000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000')
+        self.assertEqual(ip.strCompressed(),'dead:beef::/48')
+        self.assertEqual(ip.prefixlen(), 48)
+        self.assertEqual(ip.version(), 6)
+        self.assertEqual(ip.strNetmask(),'/48')
+        self.assertEqual(str(ip.netmask()),'ffff:ffff:ffff:0000:0000:0000:0000:0000')
+        self.assertEqual(ip.iptype(),'UNASSIGNED')
+        self.assertEqual(ip.reverseName(),'0.0.0.0.f.e.e.b.d.a.e.d.ip6.int.')
+        self.assertEqual(str(ip.broadcast()),'dead:beef:0000:ffff:ffff:ffff:ffff:ffff')
+        
+        ip = IPy.IP('202.31.4/24')
+        self.assertEqual(str(ip.net()),'202.31.4.0')
+
+        # TODO: fix this in IPy ... after rereading the RfC
+        # ip = IPy.IP(':1/128');
+        #$T->ok_eq ($ip->error(),'Invalid address :1 (starts with :)',$ip->error());
+        #$T->ok_eqnum ($ip->errno(),109,$ip->error());
+
+        ip = IPy.IP('ff00:0:f000::')
+        ip2 = IPy.IP('0:0:1000::')
+        self.assertEqual(IPy.IP(ip.int() + ip2.int()).strCompressed(), 'ff00:1::')
+    
+        ip = IPy.IP('::e000:0/112')
+        ip2 = IPy.IP('::e001:0/112')
+        self.assertEqual(ip.__add__(ip2).prefixlen(),111)
+        
+        ip2 = IPy.IP('::dfff:ffff')
+        #$T->ok_eqnum ($ip->bincomp('gt',$ip2),1,$ip->error());
+        
+        #ip = IPy.IP('::e000:0 - ::e002:42')
+        #$T->ok_eq (($ip->find_prefixes())[2],'0000:0000:0000:0000:0000:0000:e002:0040/127',$ip->error());
+        
+        ip = IPy.IP('ffff::/16')
+        ip2 = IPy.IP('8000::/16')
+        #$T->ok_eqnum ($ip->overlaps($ip2),$IP_NO_OVERLAP,$ip->error());
+
+if __name__ == "__main__":
+    unittest.main()
+                




More information about the Python-modules-commits mailing list