Merge lp:~logan/ubuntu/quantal/python-ipcalc/new-upstream into lp:ubuntu/quantal/python-ipcalc

Proposed by Logan Rosen
Status: Merged
Merge reported by: Dimitri John Ledkov
Merged at revision: not available
Proposed branch: lp:~logan/ubuntu/quantal/python-ipcalc/new-upstream
Merge into: lp:ubuntu/quantal/python-ipcalc
Diff against target: 546 lines (+256/-74)
5 files modified
PKG-INFO (+35/-4)
debian/changelog (+7/-0)
debian/control (+3/-2)
setup.py (+37/-8)
src/ipcalc.py (+174/-60)
To merge this branch: bzr merge lp:~logan/ubuntu/quantal/python-ipcalc/new-upstream
Reviewer Review Type Date Requested Status
Barry Warsaw (community) Approve
Ubuntu branches Pending
Review via email: mp+116586@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Barry Warsaw (barry) wrote :

Thanks for another fine contribution to Ubuntu. As with your others, please do file a bug in Debian, link it to a bug in Launchpad, and include your diff in the Debian bug. This way, it will be easier for us to resync to Debian once the newer version is available there.

One other thing I should mention. You bumped Standards-Version but it's not entirely clear to me that you verified that the package adheres to the updated version. Here's a good checklist for ensuring that your package is properly compatible with the newer version:

http://www.debian.org/doc/packaging-manuals/upgrading-checklist.txt

It's okay not to include the details of that in your changelog, but it would be helpful if you did provide the details in your merge proposal.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'PKG-INFO'
--- PKG-INFO 2009-06-17 01:33:25 +0000
+++ PKG-INFO 2012-07-25 06:05:20 +0000
@@ -1,13 +1,44 @@
1Metadata-Version: 1.01Metadata-Version: 1.0
2Name: ipcalc2Name: ipcalc
3Version: 0.33Version: 0.5.2
4Summary: IP subnet calculator4Summary: IP subnet calculator
5Home-page: http://dev.tehmaze.com/projects/ipcalc5Home-page: http://tehmaze.github.com/ipcalc
6Author: Wijnand Modderman6Author: Wijnand Modderman
7Author-email: python@tehmaze.com7Author-email: python@tehmaze.com
8License: UNKNOWN8License: UNKNOWN
9Description: 9Description:
10 This module allows you to perform IP subnet calculations, there is support10 About
11 for both IPv4 and IPv6 CIDR notation.11 =====
12
13 This module allows you to perform IP subnet calculations, there is support for
14 both IPv4 and IPv6 CIDR notation.
15
16 Example Usage
17 =============
18
19 ::
20
21 >>> import ipcalc
22 >>> for x in ipcalc.Network('172.16.42.0/30'):
23 ... print str(x)
24 ...
25 172.16.42.0
26 172.16.42.1
27 172.16.42.2
28 172.16.42.3
29 >>> subnet = ipcalc.Network('2001:beef:babe::/48')
30 >>> print str(subnet.network())
31 2001:beef:babe:0000:0000:0000:0000:0000
32 >>> print str(subnet.netmask())
33 ffff:ffff:ffff:0000:0000:0000:0000:0000
34 >>> '192.168.42.23' in Network('192.168.42.0/24')
35 True
36 >>> long(IP('fe80::213:ceff:fee8:c937'))
37 338288524927261089654168587652869703991L
38
39 Bugs/Features
40 =============
41
42 You can issue a ticket in GitHub: https://github.com/tehmaze/ipcalc/issues
12 43
13Platform: UNKNOWN44Platform: UNKNOWN
1445
=== modified file 'debian/changelog'
--- debian/changelog 2012-04-14 13:44:30 +0000
+++ debian/changelog 2012-07-25 06:05:20 +0000
@@ -1,3 +1,10 @@
1python-ipcalc (0.5.2-0ubuntu1) quantal; urgency=low
2
3 * New upstream release.
4 * Bump Standards-Version to 3.9.3.
5
6 -- Logan Rosen <logatronico@gmail.com> Wed, 25 Jul 2012 02:00:29 -0400
7
1python-ipcalc (0.3-1build1) precise; urgency=low8python-ipcalc (0.3-1build1) precise; urgency=low
29
3 * Rebuild to drop python2.6 dependencies and provides.10 * Rebuild to drop python2.6 dependencies and provides.
411
=== modified file 'debian/control'
--- debian/control 2009-06-17 01:33:25 +0000
+++ debian/control 2012-07-25 06:05:20 +0000
@@ -1,9 +1,10 @@
1Source: python-ipcalc1Source: python-ipcalc
2Section: python2Section: python
3Priority: optional3Priority: optional
4Maintainer: MEZGANI Ali <mezgani@linuxmail.org>4Maintainer: Ubuntu Developers <ubuntu-devel-discuss@lists.ubuntu.com>
5XSBC-Original-Maintainer: MEZGANI Ali <mezgani@linuxmail.org>
5Build-Depends: debhelper (>= 7), python-support, python-dev 6Build-Depends: debhelper (>= 7), python-support, python-dev
6Standards-Version: 3.8.2 7Standards-Version: 3.9.3
7Homepage: http://dev.tehmaze.com/projects/ipcalc8Homepage: http://dev.tehmaze.com/projects/ipcalc
8XB-Python-Version: ${python:Versions}9XB-Python-Version: ${python:Versions}
910
1011
=== modified file 'setup.py'
--- setup.py 2009-06-17 01:33:25 +0000
+++ setup.py 2012-07-25 06:05:20 +0000
@@ -2,18 +2,47 @@
22
3from distutils.core import setup3from distutils.core import setup
44
5long_description = '''
6This module allows you to perform IP subnet calculations, there is support
7for both IPv4 and IPv6 CIDR notation.
8'''
9
10setup(name='ipcalc',5setup(name='ipcalc',
11 version='0.3',6 version='0.5.2',
12 description='IP subnet calculator',7 description='IP subnet calculator',
13 long_description=long_description,8 long_description='''
9About
10=====
11
12This module allows you to perform IP subnet calculations, there is support for
13both IPv4 and IPv6 CIDR notation.
14
15Example Usage
16=============
17
18::
19
20 >>> import ipcalc
21 >>> for x in ipcalc.Network('172.16.42.0/30'):
22 ... print str(x)
23 ...
24 172.16.42.0
25 172.16.42.1
26 172.16.42.2
27 172.16.42.3
28 >>> subnet = ipcalc.Network('2001:beef:babe::/48')
29 >>> print str(subnet.network())
30 2001:beef:babe:0000:0000:0000:0000:0000
31 >>> print str(subnet.netmask())
32 ffff:ffff:ffff:0000:0000:0000:0000:0000
33 >>> '192.168.42.23' in Network('192.168.42.0/24')
34 True
35 >>> long(IP('fe80::213:ceff:fee8:c937'))
36 338288524927261089654168587652869703991L
37
38Bugs/Features
39=============
40
41You can issue a ticket in GitHub: https://github.com/tehmaze/ipcalc/issues
42''',
14 author='Wijnand Modderman',43 author='Wijnand Modderman',
15 author_email='python@tehmaze.com',44 author_email='python@tehmaze.com',
16 url='http://dev.tehmaze.com/projects/ipcalc',45 url='http://tehmaze.github.com/ipcalc',
17 packages = [''],46 packages = [''],
18 package_dir = {'': 'src'},47 package_dir = {'': 'src'},
19 )48 )
2049
=== modified file 'src/ipcalc.py'
--- src/ipcalc.py 2009-06-17 01:33:25 +0000
+++ src/ipcalc.py 2012-07-25 06:05:20 +0000
@@ -1,44 +1,96 @@
1# IP subnet calculator1# -*- coding: utf-8 -*-
2# (C) 2007 Wijnand 'tehmaze' Modderman - http://tehmaze.com2
3# BSD License3'''
4#4====================================
5# ABOUT5 :mod:`ipcalc` IP subnet calculator
6# This module allows you to perform network calculations.6====================================
7#7.. moduleauthor:: Wijnand Modderman <http://tehmaze.com/>
8# CHANGELOG8.. note:: BSD License
9# 2009-03-23: Added IPv4 short-hand form support, thanks to VeXocide.9
10# 2007-10-26: Added IPv6 support, as well as a lot of other functions, 10About
11# refactored the calculations.11=====
12# 2007-10-25: Initial writeup, because I could not find any other workable12
13# implementation.13This module allows you to perform network calculations.
14#14
15# TODO15Changelog
16# * add CLI parser16=========
17#17
18# REFERENCES18 ========== ===============================================================
19# * http://www.estoile.com/links/ipv6.pdf19 Date Changes
20# * http://www.iana.org/assignments/ipv4-address-space20 ========== ===============================================================
21# * http://www.iana.org/assignments/multicast-addresses21 2009-04-11 Added docstrings.
22# * http://www.iana.org/assignments/ipv6-address-space22 2009-03-23 Added IPv4 short-hand form support, thanks to VeXocide.
23# * http://www.iana.org/assignments/ipv6-tla-assignments23 2007-10-26 Added IPv6 support, as well as a lot of other functions,
24# * http://www.iana.org/assignments/ipv6-multicast-addresses24 refactored the calculations.
25# * http://www.iana.org/assignments/ipv6-anycast-addresses25 2007-10-25 Initial writeup, because I could not find any other workable
26#26 implementation.
27# THANKS (testing, tips)27 ========== ===============================================================
28# * Bastiaan (trbs)28
29# * Peter van Dijk (Habbie)29Todo
30# * Hans van Kranenburg (Knorrie)30====
31# * Jeroen Habraken (VeXocide)31
32#32Todo:
3333 * add CLI parser
34__version__ = '0.3'34
3535References
36import types, socket36==========
37
38References:
39 * http://www.estoile.com/links/ipv6.pdf
40 * http://www.iana.org/assignments/ipv4-address-space
41 * http://www.iana.org/assignments/multicast-addresses
42 * http://www.iana.org/assignments/ipv6-address-space
43 * http://www.iana.org/assignments/ipv6-tla-assignments
44 * http://www.iana.org/assignments/ipv6-multicast-addresses
45 * http://www.iana.org/assignments/ipv6-anycast-addresses
46
47Thanks
48======
49
50I wish to thank the following people for their input:
51 * Bastiaan (trbs)
52 * Peter van Dijk (Habbie)
53 * Hans van Kranenburg (Knorrie)
54 * Jeroen Habraken (VeXocide)
55 * Torbjörn Lönnemark
56
57'''
58
59__version__ = '0.5.2'
60
61import socket
62
63
64try:
65 bin(42)
66except NameError:
67 def bin(x):
68 '''
69 Stringifies an int or long in base 2.
70 '''
71 if x < 0:
72 return '-' + bin(-x)
73 out = []
74 if x == 0:
75 out.append('0')
76 while x > 0:
77 out.append('01'[x & 1])
78 x >>= 1
79 pass
80 try:
81 return '0b' + ''.join(reversed(out))
82 except NameError, ne2:
83 out.reverse()
84 return '0b' + ''.join(out)
85
3786
38class IP(object):87class IP(object):
39 '''88 '''
40 Represents a single IP address.89 Represents a single IP address.
4190
91 :param ip: the ip address
92 :type ip: :class:`IP` or str or long or int
93
42 >>> localhost = IP("127.0.0.1")94 >>> localhost = IP("127.0.0.1")
43 >>> print localhost95 >>> print localhost
44 127.0.0.196 127.0.0.1
@@ -109,12 +161,14 @@
109 self.mask = mask161 self.mask = mask
110 self.v = 0162 self.v = 0
111 # Parse input163 # Parse input
112 if isinstance(ip, IP):164 if ip is None:
165 raise ValueError, "Can not pass None"
166 elif isinstance(ip, IP):
113 self.ip = ip.ip167 self.ip = ip.ip
114 self.dq = ip.dq168 self.dq = ip.dq
115 self.v = ip.v169 self.v = ip.v
116 self.mask = ip.mask170 self.mask = ip.mask
117 elif type(ip) in [types.IntType, types.LongType]:171 elif isinstance(ip, (int, long)):
118 self.ip = long(ip)172 self.ip = long(ip)
119 if self.ip <= 0xffffffff:173 if self.ip <= 0xffffffff:
120 self.v = version or 4174 self.v = version or 4
@@ -123,10 +177,10 @@
123 self.v = version or 4177 self.v = version or 4
124 self.dq = self._itodq(ip)178 self.dq = self._itodq(ip)
125 else:179 else:
126 # If string is in CIDR notation180 # If string is in CIDR or netmask notation
127 if '/' in ip:181 if '/' in ip:
128 ip, mask = ip.split('/', 1)182 ip, mask = ip.split('/', 1)
129 self.mask = int(mask)183 self.mask = mask
130 self.v = version or 0184 self.v = version or 0
131 self.dq = ip185 self.dq = ip
132 self.ip = self._dqtoi(ip)186 self.ip = self._dqtoi(ip)
@@ -134,13 +188,26 @@
134 # Netmask defaults to one ip188 # Netmask defaults to one ip
135 if self.mask is None:189 if self.mask is None:
136 self.mask = self.v == 4 and 32 or 128190 self.mask = self.v == 4 and 32 or 128
191 # Netmask is numeric CIDR subnet
192 elif isinstance(self.mask, (int, long)) or self.mask.isdigit():
193 self.mask = int(self.mask)
194 # Netmask is in subnet notation
195 elif isinstance(self.mask, basestring):
196 limit = [32, 128][':' in self.mask]
197 inverted = ~self._dqtoi(self.mask)
198 count = 0
199 while inverted & 2**count:
200 count += 1
201 self.mask = (limit - count)
202 else:
203 raise ValueError, "Invalid netmask"
137 # Validate subnet size204 # Validate subnet size
138 if self.v == 6:205 if self.v == 6:
139 self.dq = self._itodq(self.ip)206 self.dq = self._itodq(self.ip)
140 if self.mask < 0 or self.mask > 128:207 if not 0 <= self.mask <= 128:
141 raise ValueError, "IPv6 subnet size must be between 0 and 128"208 raise ValueError, "IPv6 subnet size must be between 0 and 128"
142 elif self.v == 4:209 elif self.v == 4:
143 if self.mask < 0 or self.mask > 32:210 if not 0 <= self.mask <= 32:
144 raise ValueError, "IPv4 subnet size must be between 0 and 32"211 raise ValueError, "IPv4 subnet size must be between 0 and 32"
145212
146 def bin(self):213 def bin(self):
@@ -151,10 +218,7 @@
151 >>> print ip.bin()218 >>> print ip.bin()
152 01111111000000000000000000000001219 01111111000000000000000000000001
153 '''220 '''
154 h = hex(self.ip).lower().rstrip('l')221 return bin(self.ip).split('b')[1].rjust(self.mask, '0')
155 b = ''.join(self._bitmask[x] for x in h[2:])
156 l = self.v == 4 and 32 or 128
157 return ''.join('0' for x in xrange(len(b), l)) + b
158222
159 def hex(self):223 def hex(self):
160 '''224 '''
@@ -181,7 +245,7 @@
181 4245 4
182 '''246 '''
183 return self.v247 return self.v
184 248
185 def info(self):249 def info(self):
186 '''250 '''
187 Show IANA allocation information for the current IP address.251 Show IANA allocation information for the current IP address.
@@ -196,7 +260,7 @@
196 if self._range[self.v].has_key(b[:i]):260 if self._range[self.v].has_key(b[:i]):
197 return self._range[self.v][b[:i]]261 return self._range[self.v][b[:i]]
198 return 'UNKNOWN'262 return 'UNKNOWN'
199 263
200 def _dqtoi(self, dq):264 def _dqtoi(self, dq):
201 '''265 '''
202 Convert dotquad or hextet to long.266 Convert dotquad or hextet to long.
@@ -241,7 +305,7 @@
241 for h in hx:305 for h in hx:
242 if len(h) < 4:306 if len(h) < 4:
243 h = '%04x' % int(h, 16)307 h = '%04x' % int(h, 16)
244 if 0 > int(h, 16) > 0xffff:308 if not 0 <= int(h, 16) <= 0xffff:
245 raise ValueError, "%r: IPv6 address invalid: hextets should be between 0x0000 and 0xffff" % dq309 raise ValueError, "%r: IPv6 address invalid: hextets should be between 0x0000 and 0xffff" % dq
246 ip += h310 ip += h
247 self.v = 6311 self.v = 6
@@ -250,7 +314,7 @@
250 # Assume full heximal notation314 # Assume full heximal notation
251 self.v = 6315 self.v = 6
252 return long(h, 16)316 return long(h, 16)
253 317
254 # IPv4318 # IPv4
255 if '.' in dq:319 if '.' in dq:
256 q = dq.split('.')320 q = dq.split('.')
@@ -258,15 +322,15 @@
258 if len(q) > 4:322 if len(q) > 4:
259 raise ValueError, "%r: IPv4 address invalid: more than 4 bytes" % dq323 raise ValueError, "%r: IPv4 address invalid: more than 4 bytes" % dq
260 for x in q:324 for x in q:
261 if 0 > int(x) > 255:325 if not 0 <= int(x) <= 255:
262 raise ValueError, "%r: IPv4 address invalid: bytes should be between 0 and 255" % dq326 raise ValueError, "%r: IPv4 address invalid: bytes should be between 0 and 255" % dq
263 while len(q) < 4:327 while len(q) < 4:
264 q.insert(1, '0')328 q.insert(1, '0')
265 self.v = 4329 self.v = 4
266 return sum(long(byte) << 8 * index for index, byte in enumerate(q))330 return sum(long(byte) << 8 * index for index, byte in enumerate(q))
267 331
268 raise ValueError, "Invalid address input"332 raise ValueError, "Invalid address input"
269 333
270 def _itodq(self, n):334 def _itodq(self, n):
271 '''335 '''
272 Convert long to dotquad or hextet.336 Convert long to dotquad or hextet.
@@ -293,6 +357,21 @@
293 def __long__(self):357 def __long__(self):
294 return self.ip358 return self.ip
295359
360 def __lt__(self, other):
361 return long(self) < long(IP(other))
362
363 def __le__(self, other):
364 return long(self) <= long(IP(other))
365
366 def __ge__(self, other):
367 return long(self) >= long(IP(other))
368
369 def __gt__(self, other):
370 return long(self) > long(IP(other))
371
372 def __eq__(self, other):
373 return long(self) == long(IP(other))
374
296 def size(self):375 def size(self):
297 return 1376 return 1
298377
@@ -301,8 +380,8 @@
301 Return a new <IP> object with a copy of this one.380 Return a new <IP> object with a copy of this one.
302381
303 >>> ip = IP('127.0.0.1')382 >>> ip = IP('127.0.0.1')
304 >>> ip.clone()383 >>> ip.clone() # doctest: +ELLIPSIS
305 <ipcalc.IP object at 0xb7d4d18c>384 <ipcalc.IP object at 0x...>
306 '''385 '''
307 return IP(self)386 return IP(self)
308387
@@ -325,6 +404,25 @@
325 else:404 else:
326 return ValueError, "%r: IPv6 address is not IPv4 compatible, nor a 6-to-4 IP" % self.dq405 return ValueError, "%r: IPv6 address is not IPv4 compatible, nor a 6-to-4 IP" % self.dq
327406
407 @classmethod
408 def from_bin(cls, value):
409 value = value.lstrip('b')
410 if len(value) == 32:
411 return cls(int(value, 2))
412 elif len(value) == 128:
413 return cls(long(value, 2))
414 else:
415 return ValueError, "%r: invalid binary notation" % (value,)
416
417 @classmethod
418 def from_hex(cls, value):
419 if len(value) == 8:
420 return cls(int(value, 16))
421 elif len(value) == 32:
422 return cls(long(value, 16))
423 else:
424 raise ValueError, "%r: invalid hexadecimal notation" % (value,)
425
328 def to_ipv6(self, type='6-to-4'):426 def to_ipv6(self, type='6-to-4'):
329 '''427 '''
330 Convert (an IPv4) IP address to an IPv6 address.428 Convert (an IPv4) IP address to an IPv6 address.
@@ -347,11 +445,18 @@
347 Used for comparisons.445 Used for comparisons.
348 '''446 '''
349 return (self.dq, self.mask)447 return (self.dq, self.mask)
350 448
449
351class Network(IP):450class Network(IP):
352 '''451 '''
353 Network slice calculations.452 Network slice calculations.
354453
454 :param ip: network address
455 :type ip: :class:`IP` or str or long or int
456 :param mask: netmask
457 :type mask: int or str
458
459
355 >>> localnet = Network('127.0.0.1/8')460 >>> localnet = Network('127.0.0.1/8')
356 >>> print localnet461 >>> print localnet
357 127.0.0.1462 127.0.0.1
@@ -379,7 +484,7 @@
379 127.0.0.0484 127.0.0.0
380 '''485 '''
381 return IP(self.ip & long(self.netmask()), version=self.version())486 return IP(self.ip & long(self.netmask()), version=self.version())
382 487
383 def broadcast(self):488 def broadcast(self):
384 '''489 '''
385 Broadcast address.490 Broadcast address.
@@ -441,6 +546,9 @@
441 def __ge__(self, other):546 def __ge__(self, other):
442 return self.size() >= IP(other).size()547 return self.size() >= IP(other).size()
443548
549 def __eq__(self, other):
550 return self.size() == IP(other).size()
551
444 def __iter__(self):552 def __iter__(self):
445 '''553 '''
446 Generate a range of ip addresses within the network.554 Generate a range of ip addresses within the network.
@@ -453,13 +561,16 @@
453 192.168.114.2561 192.168.114.2
454 192.168.114.3562 192.168.114.3
455 '''563 '''
456 for ip in [IP(long(self)+x) for x in xrange(0, self.size())]:564 for ip in (IP(long(self)+x) for x in xrange(0, self.size())):
457 yield ip565 yield ip
458566
459 def has_key(self, ip):567 def has_key(self, ip):
460 '''568 '''
461 Check if the given ip is part of the network.569 Check if the given ip is part of the network.
462570
571 :param ip: the ip address
572 :type ip: :class:`IP` or str or long or int
573
463 >>> net = Network('192.0.2.0/24')574 >>> net = Network('192.0.2.0/24')
464 >>> net.has_key('192.168.2.0')575 >>> net.has_key('192.168.2.0')
465 False576 False
@@ -478,12 +589,16 @@
478 '''589 '''
479 return 2 ** ((self.version() == 4 and 32 or 128) - self.mask)590 return 2 ** ((self.version() == 4 and 32 or 128) - self.mask)
480591
592
481if __name__ == '__main__':593if __name__ == '__main__':
482 tests = [594 tests = [
483 ('192.168.114.42', 23, ['192.168.0.1', '192.168.114.128', '10.0.0.1']),595 ('192.168.114.42', 23, ['192.168.0.1', '192.168.114.128', '10.0.0.1']),
484 ('123::', 128, ['123:456::', '::1', '123::456']),596 ('123::', 128, ['123:456::', '::1', '123::456']),
485 ('::42', 64, ['::1', '1::']),597 ('::42', 64, ['::1', '1::']),
486 ('2001:dead:beef:1:c01d:c01a::', 48, ['2001:dead:beef:babe::'])598 ('2001:dead:beef:1:c01d:c01a::', 48, ['2001:dead:beef:babe::']),
599 ('10.10.0.0', '255.255.255.0', ['10.10.0.20', '10.10.10.20']),
600 ('2001:dead:beef:1:c01d:c01a::', 'ffff:ffff:ffff::', ['2001:dead:beef:babe::']),
601 ('10.10.0.0/255.255.240.0', None, ['10.10.0.20', '10.10.250.0']),
487 ]602 ]
488603
489 for ip, mask, test_ip in tests:604 for ip, mask, test_ip in tests:
@@ -506,4 +621,3 @@
506 print 'last host.:', net.host_last()621 print 'last host.:', net.host_last()
507 for ip in test_ip:622 for ip in test_ip:
508 print '%s in network: ' % ip, ip in net623 print '%s in network: ' % ip, ip in net
509

Subscribers

People subscribed via source and target branches

to all changes: