Merge lp:~logan/ubuntu/quantal/python-ipcalc/new-upstream into lp:ubuntu/quantal/python-ipcalc
- Quantal (12.10)
- new-upstream
- Merge into quantal
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 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Barry Warsaw (community) | Approve | ||
Ubuntu branches | Pending | ||
Review via email: mp+116586@code.launchpad.net |
Commit message
Description of the change
To post a comment you must log in.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'PKG-INFO' | |||
2 | --- PKG-INFO 2009-06-17 01:33:25 +0000 | |||
3 | +++ PKG-INFO 2012-07-25 06:05:20 +0000 | |||
4 | @@ -1,13 +1,44 @@ | |||
5 | 1 | Metadata-Version: 1.0 | 1 | Metadata-Version: 1.0 |
6 | 2 | Name: ipcalc | 2 | Name: ipcalc |
8 | 3 | Version: 0.3 | 3 | Version: 0.5.2 |
9 | 4 | Summary: IP subnet calculator | 4 | Summary: IP subnet calculator |
11 | 5 | Home-page: http://dev.tehmaze.com/projects/ipcalc | 5 | Home-page: http://tehmaze.github.com/ipcalc |
12 | 6 | Author: Wijnand Modderman | 6 | Author: Wijnand Modderman |
13 | 7 | Author-email: python@tehmaze.com | 7 | Author-email: python@tehmaze.com |
14 | 8 | License: UNKNOWN | 8 | License: UNKNOWN |
15 | 9 | Description: | 9 | Description: |
18 | 10 | This module allows you to perform IP subnet calculations, there is support | 10 | About |
19 | 11 | for both IPv4 and IPv6 CIDR notation. | 11 | ===== |
20 | 12 | |||
21 | 13 | This module allows you to perform IP subnet calculations, there is support for | ||
22 | 14 | both IPv4 and IPv6 CIDR notation. | ||
23 | 15 | |||
24 | 16 | Example Usage | ||
25 | 17 | ============= | ||
26 | 18 | |||
27 | 19 | :: | ||
28 | 20 | |||
29 | 21 | >>> import ipcalc | ||
30 | 22 | >>> for x in ipcalc.Network('172.16.42.0/30'): | ||
31 | 23 | ... print str(x) | ||
32 | 24 | ... | ||
33 | 25 | 172.16.42.0 | ||
34 | 26 | 172.16.42.1 | ||
35 | 27 | 172.16.42.2 | ||
36 | 28 | 172.16.42.3 | ||
37 | 29 | >>> subnet = ipcalc.Network('2001:beef:babe::/48') | ||
38 | 30 | >>> print str(subnet.network()) | ||
39 | 31 | 2001:beef:babe:0000:0000:0000:0000:0000 | ||
40 | 32 | >>> print str(subnet.netmask()) | ||
41 | 33 | ffff:ffff:ffff:0000:0000:0000:0000:0000 | ||
42 | 34 | >>> '192.168.42.23' in Network('192.168.42.0/24') | ||
43 | 35 | True | ||
44 | 36 | >>> long(IP('fe80::213:ceff:fee8:c937')) | ||
45 | 37 | 338288524927261089654168587652869703991L | ||
46 | 38 | |||
47 | 39 | Bugs/Features | ||
48 | 40 | ============= | ||
49 | 41 | |||
50 | 42 | You can issue a ticket in GitHub: https://github.com/tehmaze/ipcalc/issues | ||
51 | 12 | 43 | ||
52 | 13 | Platform: UNKNOWN | 44 | Platform: UNKNOWN |
53 | 14 | 45 | ||
54 | === modified file 'debian/changelog' | |||
55 | --- debian/changelog 2012-04-14 13:44:30 +0000 | |||
56 | +++ debian/changelog 2012-07-25 06:05:20 +0000 | |||
57 | @@ -1,3 +1,10 @@ | |||
58 | 1 | python-ipcalc (0.5.2-0ubuntu1) quantal; urgency=low | ||
59 | 2 | |||
60 | 3 | * New upstream release. | ||
61 | 4 | * Bump Standards-Version to 3.9.3. | ||
62 | 5 | |||
63 | 6 | -- Logan Rosen <logatronico@gmail.com> Wed, 25 Jul 2012 02:00:29 -0400 | ||
64 | 7 | |||
65 | 1 | python-ipcalc (0.3-1build1) precise; urgency=low | 8 | python-ipcalc (0.3-1build1) precise; urgency=low |
66 | 2 | 9 | ||
67 | 3 | * Rebuild to drop python2.6 dependencies and provides. | 10 | * Rebuild to drop python2.6 dependencies and provides. |
68 | 4 | 11 | ||
69 | === modified file 'debian/control' | |||
70 | --- debian/control 2009-06-17 01:33:25 +0000 | |||
71 | +++ debian/control 2012-07-25 06:05:20 +0000 | |||
72 | @@ -1,9 +1,10 @@ | |||
73 | 1 | Source: python-ipcalc | 1 | Source: python-ipcalc |
74 | 2 | Section: python | 2 | Section: python |
75 | 3 | Priority: optional | 3 | Priority: optional |
77 | 4 | Maintainer: MEZGANI Ali <mezgani@linuxmail.org> | 4 | Maintainer: Ubuntu Developers <ubuntu-devel-discuss@lists.ubuntu.com> |
78 | 5 | XSBC-Original-Maintainer: MEZGANI Ali <mezgani@linuxmail.org> | ||
79 | 5 | Build-Depends: debhelper (>= 7), python-support, python-dev | 6 | Build-Depends: debhelper (>= 7), python-support, python-dev |
81 | 6 | Standards-Version: 3.8.2 | 7 | Standards-Version: 3.9.3 |
82 | 7 | Homepage: http://dev.tehmaze.com/projects/ipcalc | 8 | Homepage: http://dev.tehmaze.com/projects/ipcalc |
83 | 8 | XB-Python-Version: ${python:Versions} | 9 | XB-Python-Version: ${python:Versions} |
84 | 9 | 10 | ||
85 | 10 | 11 | ||
86 | === modified file 'setup.py' | |||
87 | --- setup.py 2009-06-17 01:33:25 +0000 | |||
88 | +++ setup.py 2012-07-25 06:05:20 +0000 | |||
89 | @@ -2,18 +2,47 @@ | |||
90 | 2 | 2 | ||
91 | 3 | from distutils.core import setup | 3 | from distutils.core import setup |
92 | 4 | 4 | ||
93 | 5 | long_description = ''' | ||
94 | 6 | This module allows you to perform IP subnet calculations, there is support | ||
95 | 7 | for both IPv4 and IPv6 CIDR notation. | ||
96 | 8 | ''' | ||
97 | 9 | |||
98 | 10 | setup(name='ipcalc', | 5 | setup(name='ipcalc', |
100 | 11 | version='0.3', | 6 | version='0.5.2', |
101 | 12 | description='IP subnet calculator', | 7 | description='IP subnet calculator', |
103 | 13 | long_description=long_description, | 8 | long_description=''' |
104 | 9 | About | ||
105 | 10 | ===== | ||
106 | 11 | |||
107 | 12 | This module allows you to perform IP subnet calculations, there is support for | ||
108 | 13 | both IPv4 and IPv6 CIDR notation. | ||
109 | 14 | |||
110 | 15 | Example Usage | ||
111 | 16 | ============= | ||
112 | 17 | |||
113 | 18 | :: | ||
114 | 19 | |||
115 | 20 | >>> import ipcalc | ||
116 | 21 | >>> for x in ipcalc.Network('172.16.42.0/30'): | ||
117 | 22 | ... print str(x) | ||
118 | 23 | ... | ||
119 | 24 | 172.16.42.0 | ||
120 | 25 | 172.16.42.1 | ||
121 | 26 | 172.16.42.2 | ||
122 | 27 | 172.16.42.3 | ||
123 | 28 | >>> subnet = ipcalc.Network('2001:beef:babe::/48') | ||
124 | 29 | >>> print str(subnet.network()) | ||
125 | 30 | 2001:beef:babe:0000:0000:0000:0000:0000 | ||
126 | 31 | >>> print str(subnet.netmask()) | ||
127 | 32 | ffff:ffff:ffff:0000:0000:0000:0000:0000 | ||
128 | 33 | >>> '192.168.42.23' in Network('192.168.42.0/24') | ||
129 | 34 | True | ||
130 | 35 | >>> long(IP('fe80::213:ceff:fee8:c937')) | ||
131 | 36 | 338288524927261089654168587652869703991L | ||
132 | 37 | |||
133 | 38 | Bugs/Features | ||
134 | 39 | ============= | ||
135 | 40 | |||
136 | 41 | You can issue a ticket in GitHub: https://github.com/tehmaze/ipcalc/issues | ||
137 | 42 | ''', | ||
138 | 14 | author='Wijnand Modderman', | 43 | author='Wijnand Modderman', |
139 | 15 | author_email='python@tehmaze.com', | 44 | author_email='python@tehmaze.com', |
141 | 16 | url='http://dev.tehmaze.com/projects/ipcalc', | 45 | url='http://tehmaze.github.com/ipcalc', |
142 | 17 | packages = [''], | 46 | packages = [''], |
143 | 18 | package_dir = {'': 'src'}, | 47 | package_dir = {'': 'src'}, |
144 | 19 | ) | 48 | ) |
145 | 20 | 49 | ||
146 | === modified file 'src/ipcalc.py' | |||
147 | --- src/ipcalc.py 2009-06-17 01:33:25 +0000 | |||
148 | +++ src/ipcalc.py 2012-07-25 06:05:20 +0000 | |||
149 | @@ -1,44 +1,96 @@ | |||
186 | 1 | # IP subnet calculator | 1 | # -*- coding: utf-8 -*- |
187 | 2 | # (C) 2007 Wijnand 'tehmaze' Modderman - http://tehmaze.com | 2 | |
188 | 3 | # BSD License | 3 | ''' |
189 | 4 | # | 4 | ==================================== |
190 | 5 | # ABOUT | 5 | :mod:`ipcalc` IP subnet calculator |
191 | 6 | # This module allows you to perform network calculations. | 6 | ==================================== |
192 | 7 | # | 7 | .. moduleauthor:: Wijnand Modderman <http://tehmaze.com/> |
193 | 8 | # CHANGELOG | 8 | .. note:: BSD License |
194 | 9 | # 2009-03-23: Added IPv4 short-hand form support, thanks to VeXocide. | 9 | |
195 | 10 | # 2007-10-26: Added IPv6 support, as well as a lot of other functions, | 10 | About |
196 | 11 | # refactored the calculations. | 11 | ===== |
197 | 12 | # 2007-10-25: Initial writeup, because I could not find any other workable | 12 | |
198 | 13 | # implementation. | 13 | This module allows you to perform network calculations. |
199 | 14 | # | 14 | |
200 | 15 | # TODO | 15 | Changelog |
201 | 16 | # * add CLI parser | 16 | ========= |
202 | 17 | # | 17 | |
203 | 18 | # REFERENCES | 18 | ========== =============================================================== |
204 | 19 | # * http://www.estoile.com/links/ipv6.pdf | 19 | Date Changes |
205 | 20 | # * http://www.iana.org/assignments/ipv4-address-space | 20 | ========== =============================================================== |
206 | 21 | # * http://www.iana.org/assignments/multicast-addresses | 21 | 2009-04-11 Added docstrings. |
207 | 22 | # * http://www.iana.org/assignments/ipv6-address-space | 22 | 2009-03-23 Added IPv4 short-hand form support, thanks to VeXocide. |
208 | 23 | # * http://www.iana.org/assignments/ipv6-tla-assignments | 23 | 2007-10-26 Added IPv6 support, as well as a lot of other functions, |
209 | 24 | # * http://www.iana.org/assignments/ipv6-multicast-addresses | 24 | refactored the calculations. |
210 | 25 | # * http://www.iana.org/assignments/ipv6-anycast-addresses | 25 | 2007-10-25 Initial writeup, because I could not find any other workable |
211 | 26 | # | 26 | implementation. |
212 | 27 | # THANKS (testing, tips) | 27 | ========== =============================================================== |
213 | 28 | # * Bastiaan (trbs) | 28 | |
214 | 29 | # * Peter van Dijk (Habbie) | 29 | Todo |
215 | 30 | # * Hans van Kranenburg (Knorrie) | 30 | ==== |
216 | 31 | # * Jeroen Habraken (VeXocide) | 31 | |
217 | 32 | # | 32 | Todo: |
218 | 33 | 33 | * add CLI parser | |
219 | 34 | __version__ = '0.3' | 34 | |
220 | 35 | 35 | References | |
221 | 36 | import types, socket | 36 | ========== |
222 | 37 | |||
223 | 38 | References: | ||
224 | 39 | * http://www.estoile.com/links/ipv6.pdf | ||
225 | 40 | * http://www.iana.org/assignments/ipv4-address-space | ||
226 | 41 | * http://www.iana.org/assignments/multicast-addresses | ||
227 | 42 | * http://www.iana.org/assignments/ipv6-address-space | ||
228 | 43 | * http://www.iana.org/assignments/ipv6-tla-assignments | ||
229 | 44 | * http://www.iana.org/assignments/ipv6-multicast-addresses | ||
230 | 45 | * http://www.iana.org/assignments/ipv6-anycast-addresses | ||
231 | 46 | |||
232 | 47 | Thanks | ||
233 | 48 | ====== | ||
234 | 49 | |||
235 | 50 | I wish to thank the following people for their input: | ||
236 | 51 | * Bastiaan (trbs) | ||
237 | 52 | * Peter van Dijk (Habbie) | ||
238 | 53 | * Hans van Kranenburg (Knorrie) | ||
239 | 54 | * Jeroen Habraken (VeXocide) | ||
240 | 55 | * Torbjörn Lönnemark | ||
241 | 56 | |||
242 | 57 | ''' | ||
243 | 58 | |||
244 | 59 | __version__ = '0.5.2' | ||
245 | 60 | |||
246 | 61 | import socket | ||
247 | 62 | |||
248 | 63 | |||
249 | 64 | try: | ||
250 | 65 | bin(42) | ||
251 | 66 | except NameError: | ||
252 | 67 | def bin(x): | ||
253 | 68 | ''' | ||
254 | 69 | Stringifies an int or long in base 2. | ||
255 | 70 | ''' | ||
256 | 71 | if x < 0: | ||
257 | 72 | return '-' + bin(-x) | ||
258 | 73 | out = [] | ||
259 | 74 | if x == 0: | ||
260 | 75 | out.append('0') | ||
261 | 76 | while x > 0: | ||
262 | 77 | out.append('01'[x & 1]) | ||
263 | 78 | x >>= 1 | ||
264 | 79 | pass | ||
265 | 80 | try: | ||
266 | 81 | return '0b' + ''.join(reversed(out)) | ||
267 | 82 | except NameError, ne2: | ||
268 | 83 | out.reverse() | ||
269 | 84 | return '0b' + ''.join(out) | ||
270 | 85 | |||
271 | 37 | 86 | ||
272 | 38 | class IP(object): | 87 | class IP(object): |
273 | 39 | ''' | 88 | ''' |
274 | 40 | Represents a single IP address. | 89 | Represents a single IP address. |
275 | 41 | 90 | ||
276 | 91 | :param ip: the ip address | ||
277 | 92 | :type ip: :class:`IP` or str or long or int | ||
278 | 93 | |||
279 | 42 | >>> localhost = IP("127.0.0.1") | 94 | >>> localhost = IP("127.0.0.1") |
280 | 43 | >>> print localhost | 95 | >>> print localhost |
281 | 44 | 127.0.0.1 | 96 | 127.0.0.1 |
282 | @@ -109,12 +161,14 @@ | |||
283 | 109 | self.mask = mask | 161 | self.mask = mask |
284 | 110 | self.v = 0 | 162 | self.v = 0 |
285 | 111 | # Parse input | 163 | # Parse input |
287 | 112 | if isinstance(ip, IP): | 164 | if ip is None: |
288 | 165 | raise ValueError, "Can not pass None" | ||
289 | 166 | elif isinstance(ip, IP): | ||
290 | 113 | self.ip = ip.ip | 167 | self.ip = ip.ip |
291 | 114 | self.dq = ip.dq | 168 | self.dq = ip.dq |
292 | 115 | self.v = ip.v | 169 | self.v = ip.v |
293 | 116 | self.mask = ip.mask | 170 | self.mask = ip.mask |
295 | 117 | elif type(ip) in [types.IntType, types.LongType]: | 171 | elif isinstance(ip, (int, long)): |
296 | 118 | self.ip = long(ip) | 172 | self.ip = long(ip) |
297 | 119 | if self.ip <= 0xffffffff: | 173 | if self.ip <= 0xffffffff: |
298 | 120 | self.v = version or 4 | 174 | self.v = version or 4 |
299 | @@ -123,10 +177,10 @@ | |||
300 | 123 | self.v = version or 4 | 177 | self.v = version or 4 |
301 | 124 | self.dq = self._itodq(ip) | 178 | self.dq = self._itodq(ip) |
302 | 125 | else: | 179 | else: |
304 | 126 | # If string is in CIDR notation | 180 | # If string is in CIDR or netmask notation |
305 | 127 | if '/' in ip: | 181 | if '/' in ip: |
306 | 128 | ip, mask = ip.split('/', 1) | 182 | ip, mask = ip.split('/', 1) |
308 | 129 | self.mask = int(mask) | 183 | self.mask = mask |
309 | 130 | self.v = version or 0 | 184 | self.v = version or 0 |
310 | 131 | self.dq = ip | 185 | self.dq = ip |
311 | 132 | self.ip = self._dqtoi(ip) | 186 | self.ip = self._dqtoi(ip) |
312 | @@ -134,13 +188,26 @@ | |||
313 | 134 | # Netmask defaults to one ip | 188 | # Netmask defaults to one ip |
314 | 135 | if self.mask is None: | 189 | if self.mask is None: |
315 | 136 | self.mask = self.v == 4 and 32 or 128 | 190 | self.mask = self.v == 4 and 32 or 128 |
316 | 191 | # Netmask is numeric CIDR subnet | ||
317 | 192 | elif isinstance(self.mask, (int, long)) or self.mask.isdigit(): | ||
318 | 193 | self.mask = int(self.mask) | ||
319 | 194 | # Netmask is in subnet notation | ||
320 | 195 | elif isinstance(self.mask, basestring): | ||
321 | 196 | limit = [32, 128][':' in self.mask] | ||
322 | 197 | inverted = ~self._dqtoi(self.mask) | ||
323 | 198 | count = 0 | ||
324 | 199 | while inverted & 2**count: | ||
325 | 200 | count += 1 | ||
326 | 201 | self.mask = (limit - count) | ||
327 | 202 | else: | ||
328 | 203 | raise ValueError, "Invalid netmask" | ||
329 | 137 | # Validate subnet size | 204 | # Validate subnet size |
330 | 138 | if self.v == 6: | 205 | if self.v == 6: |
331 | 139 | self.dq = self._itodq(self.ip) | 206 | self.dq = self._itodq(self.ip) |
333 | 140 | if self.mask < 0 or self.mask > 128: | 207 | if not 0 <= self.mask <= 128: |
334 | 141 | raise ValueError, "IPv6 subnet size must be between 0 and 128" | 208 | raise ValueError, "IPv6 subnet size must be between 0 and 128" |
335 | 142 | elif self.v == 4: | 209 | elif self.v == 4: |
337 | 143 | if self.mask < 0 or self.mask > 32: | 210 | if not 0 <= self.mask <= 32: |
338 | 144 | raise ValueError, "IPv4 subnet size must be between 0 and 32" | 211 | raise ValueError, "IPv4 subnet size must be between 0 and 32" |
339 | 145 | 212 | ||
340 | 146 | def bin(self): | 213 | def bin(self): |
341 | @@ -151,10 +218,7 @@ | |||
342 | 151 | >>> print ip.bin() | 218 | >>> print ip.bin() |
343 | 152 | 01111111000000000000000000000001 | 219 | 01111111000000000000000000000001 |
344 | 153 | ''' | 220 | ''' |
349 | 154 | h = hex(self.ip).lower().rstrip('l') | 221 | return bin(self.ip).split('b')[1].rjust(self.mask, '0') |
346 | 155 | b = ''.join(self._bitmask[x] for x in h[2:]) | ||
347 | 156 | l = self.v == 4 and 32 or 128 | ||
348 | 157 | return ''.join('0' for x in xrange(len(b), l)) + b | ||
350 | 158 | 222 | ||
351 | 159 | def hex(self): | 223 | def hex(self): |
352 | 160 | ''' | 224 | ''' |
353 | @@ -181,7 +245,7 @@ | |||
354 | 181 | 4 | 245 | 4 |
355 | 182 | ''' | 246 | ''' |
356 | 183 | return self.v | 247 | return self.v |
358 | 184 | 248 | ||
359 | 185 | def info(self): | 249 | def info(self): |
360 | 186 | ''' | 250 | ''' |
361 | 187 | Show IANA allocation information for the current IP address. | 251 | Show IANA allocation information for the current IP address. |
362 | @@ -196,7 +260,7 @@ | |||
363 | 196 | if self._range[self.v].has_key(b[:i]): | 260 | if self._range[self.v].has_key(b[:i]): |
364 | 197 | return self._range[self.v][b[:i]] | 261 | return self._range[self.v][b[:i]] |
365 | 198 | return 'UNKNOWN' | 262 | return 'UNKNOWN' |
367 | 199 | 263 | ||
368 | 200 | def _dqtoi(self, dq): | 264 | def _dqtoi(self, dq): |
369 | 201 | ''' | 265 | ''' |
370 | 202 | Convert dotquad or hextet to long. | 266 | Convert dotquad or hextet to long. |
371 | @@ -241,7 +305,7 @@ | |||
372 | 241 | for h in hx: | 305 | for h in hx: |
373 | 242 | if len(h) < 4: | 306 | if len(h) < 4: |
374 | 243 | h = '%04x' % int(h, 16) | 307 | h = '%04x' % int(h, 16) |
376 | 244 | if 0 > int(h, 16) > 0xffff: | 308 | if not 0 <= int(h, 16) <= 0xffff: |
377 | 245 | raise ValueError, "%r: IPv6 address invalid: hextets should be between 0x0000 and 0xffff" % dq | 309 | raise ValueError, "%r: IPv6 address invalid: hextets should be between 0x0000 and 0xffff" % dq |
378 | 246 | ip += h | 310 | ip += h |
379 | 247 | self.v = 6 | 311 | self.v = 6 |
380 | @@ -250,7 +314,7 @@ | |||
381 | 250 | # Assume full heximal notation | 314 | # Assume full heximal notation |
382 | 251 | self.v = 6 | 315 | self.v = 6 |
383 | 252 | return long(h, 16) | 316 | return long(h, 16) |
385 | 253 | 317 | ||
386 | 254 | # IPv4 | 318 | # IPv4 |
387 | 255 | if '.' in dq: | 319 | if '.' in dq: |
388 | 256 | q = dq.split('.') | 320 | q = dq.split('.') |
389 | @@ -258,15 +322,15 @@ | |||
390 | 258 | if len(q) > 4: | 322 | if len(q) > 4: |
391 | 259 | raise ValueError, "%r: IPv4 address invalid: more than 4 bytes" % dq | 323 | raise ValueError, "%r: IPv4 address invalid: more than 4 bytes" % dq |
392 | 260 | for x in q: | 324 | for x in q: |
394 | 261 | if 0 > int(x) > 255: | 325 | if not 0 <= int(x) <= 255: |
395 | 262 | raise ValueError, "%r: IPv4 address invalid: bytes should be between 0 and 255" % dq | 326 | raise ValueError, "%r: IPv4 address invalid: bytes should be between 0 and 255" % dq |
396 | 263 | while len(q) < 4: | 327 | while len(q) < 4: |
397 | 264 | q.insert(1, '0') | 328 | q.insert(1, '0') |
398 | 265 | self.v = 4 | 329 | self.v = 4 |
399 | 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)) |
401 | 267 | 331 | ||
402 | 268 | raise ValueError, "Invalid address input" | 332 | raise ValueError, "Invalid address input" |
404 | 269 | 333 | ||
405 | 270 | def _itodq(self, n): | 334 | def _itodq(self, n): |
406 | 271 | ''' | 335 | ''' |
407 | 272 | Convert long to dotquad or hextet. | 336 | Convert long to dotquad or hextet. |
408 | @@ -293,6 +357,21 @@ | |||
409 | 293 | def __long__(self): | 357 | def __long__(self): |
410 | 294 | return self.ip | 358 | return self.ip |
411 | 295 | 359 | ||
412 | 360 | def __lt__(self, other): | ||
413 | 361 | return long(self) < long(IP(other)) | ||
414 | 362 | |||
415 | 363 | def __le__(self, other): | ||
416 | 364 | return long(self) <= long(IP(other)) | ||
417 | 365 | |||
418 | 366 | def __ge__(self, other): | ||
419 | 367 | return long(self) >= long(IP(other)) | ||
420 | 368 | |||
421 | 369 | def __gt__(self, other): | ||
422 | 370 | return long(self) > long(IP(other)) | ||
423 | 371 | |||
424 | 372 | def __eq__(self, other): | ||
425 | 373 | return long(self) == long(IP(other)) | ||
426 | 374 | |||
427 | 296 | def size(self): | 375 | def size(self): |
428 | 297 | return 1 | 376 | return 1 |
429 | 298 | 377 | ||
430 | @@ -301,8 +380,8 @@ | |||
431 | 301 | Return a new <IP> object with a copy of this one. | 380 | Return a new <IP> object with a copy of this one. |
432 | 302 | 381 | ||
433 | 303 | >>> ip = IP('127.0.0.1') | 382 | >>> ip = IP('127.0.0.1') |
436 | 304 | >>> ip.clone() | 383 | >>> ip.clone() # doctest: +ELLIPSIS |
437 | 305 | <ipcalc.IP object at 0xb7d4d18c> | 384 | <ipcalc.IP object at 0x...> |
438 | 306 | ''' | 385 | ''' |
439 | 307 | return IP(self) | 386 | return IP(self) |
440 | 308 | 387 | ||
441 | @@ -325,6 +404,25 @@ | |||
442 | 325 | else: | 404 | else: |
443 | 326 | return ValueError, "%r: IPv6 address is not IPv4 compatible, nor a 6-to-4 IP" % self.dq | 405 | return ValueError, "%r: IPv6 address is not IPv4 compatible, nor a 6-to-4 IP" % self.dq |
444 | 327 | 406 | ||
445 | 407 | @classmethod | ||
446 | 408 | def from_bin(cls, value): | ||
447 | 409 | value = value.lstrip('b') | ||
448 | 410 | if len(value) == 32: | ||
449 | 411 | return cls(int(value, 2)) | ||
450 | 412 | elif len(value) == 128: | ||
451 | 413 | return cls(long(value, 2)) | ||
452 | 414 | else: | ||
453 | 415 | return ValueError, "%r: invalid binary notation" % (value,) | ||
454 | 416 | |||
455 | 417 | @classmethod | ||
456 | 418 | def from_hex(cls, value): | ||
457 | 419 | if len(value) == 8: | ||
458 | 420 | return cls(int(value, 16)) | ||
459 | 421 | elif len(value) == 32: | ||
460 | 422 | return cls(long(value, 16)) | ||
461 | 423 | else: | ||
462 | 424 | raise ValueError, "%r: invalid hexadecimal notation" % (value,) | ||
463 | 425 | |||
464 | 328 | def to_ipv6(self, type='6-to-4'): | 426 | def to_ipv6(self, type='6-to-4'): |
465 | 329 | ''' | 427 | ''' |
466 | 330 | Convert (an IPv4) IP address to an IPv6 address. | 428 | Convert (an IPv4) IP address to an IPv6 address. |
467 | @@ -347,11 +445,18 @@ | |||
468 | 347 | Used for comparisons. | 445 | Used for comparisons. |
469 | 348 | ''' | 446 | ''' |
470 | 349 | return (self.dq, self.mask) | 447 | return (self.dq, self.mask) |
472 | 350 | 448 | ||
473 | 449 | |||
474 | 351 | class Network(IP): | 450 | class Network(IP): |
475 | 352 | ''' | 451 | ''' |
476 | 353 | Network slice calculations. | 452 | Network slice calculations. |
477 | 354 | 453 | ||
478 | 454 | :param ip: network address | ||
479 | 455 | :type ip: :class:`IP` or str or long or int | ||
480 | 456 | :param mask: netmask | ||
481 | 457 | :type mask: int or str | ||
482 | 458 | |||
483 | 459 | |||
484 | 355 | >>> localnet = Network('127.0.0.1/8') | 460 | >>> localnet = Network('127.0.0.1/8') |
485 | 356 | >>> print localnet | 461 | >>> print localnet |
486 | 357 | 127.0.0.1 | 462 | 127.0.0.1 |
487 | @@ -379,7 +484,7 @@ | |||
488 | 379 | 127.0.0.0 | 484 | 127.0.0.0 |
489 | 380 | ''' | 485 | ''' |
490 | 381 | return IP(self.ip & long(self.netmask()), version=self.version()) | 486 | return IP(self.ip & long(self.netmask()), version=self.version()) |
492 | 382 | 487 | ||
493 | 383 | def broadcast(self): | 488 | def broadcast(self): |
494 | 384 | ''' | 489 | ''' |
495 | 385 | Broadcast address. | 490 | Broadcast address. |
496 | @@ -441,6 +546,9 @@ | |||
497 | 441 | def __ge__(self, other): | 546 | def __ge__(self, other): |
498 | 442 | return self.size() >= IP(other).size() | 547 | return self.size() >= IP(other).size() |
499 | 443 | 548 | ||
500 | 549 | def __eq__(self, other): | ||
501 | 550 | return self.size() == IP(other).size() | ||
502 | 551 | |||
503 | 444 | def __iter__(self): | 552 | def __iter__(self): |
504 | 445 | ''' | 553 | ''' |
505 | 446 | Generate a range of ip addresses within the network. | 554 | Generate a range of ip addresses within the network. |
506 | @@ -453,13 +561,16 @@ | |||
507 | 453 | 192.168.114.2 | 561 | 192.168.114.2 |
508 | 454 | 192.168.114.3 | 562 | 192.168.114.3 |
509 | 455 | ''' | 563 | ''' |
511 | 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())): |
512 | 457 | yield ip | 565 | yield ip |
513 | 458 | 566 | ||
514 | 459 | def has_key(self, ip): | 567 | def has_key(self, ip): |
515 | 460 | ''' | 568 | ''' |
516 | 461 | Check if the given ip is part of the network. | 569 | Check if the given ip is part of the network. |
517 | 462 | 570 | ||
518 | 571 | :param ip: the ip address | ||
519 | 572 | :type ip: :class:`IP` or str or long or int | ||
520 | 573 | |||
521 | 463 | >>> net = Network('192.0.2.0/24') | 574 | >>> net = Network('192.0.2.0/24') |
522 | 464 | >>> net.has_key('192.168.2.0') | 575 | >>> net.has_key('192.168.2.0') |
523 | 465 | False | 576 | False |
524 | @@ -478,12 +589,16 @@ | |||
525 | 478 | ''' | 589 | ''' |
526 | 479 | return 2 ** ((self.version() == 4 and 32 or 128) - self.mask) | 590 | return 2 ** ((self.version() == 4 and 32 or 128) - self.mask) |
527 | 480 | 591 | ||
528 | 592 | |||
529 | 481 | if __name__ == '__main__': | 593 | if __name__ == '__main__': |
530 | 482 | tests = [ | 594 | tests = [ |
531 | 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']), |
532 | 484 | ('123::', 128, ['123:456::', '::1', '123::456']), | 596 | ('123::', 128, ['123:456::', '::1', '123::456']), |
533 | 485 | ('::42', 64, ['::1', '1::']), | 597 | ('::42', 64, ['::1', '1::']), |
535 | 486 | ('2001:dead:beef:1:c01d:c01a::', 48, ['2001:dead:beef:babe::']) | 598 | ('2001:dead:beef:1:c01d:c01a::', 48, ['2001:dead:beef:babe::']), |
536 | 599 | ('10.10.0.0', '255.255.255.0', ['10.10.0.20', '10.10.10.20']), | ||
537 | 600 | ('2001:dead:beef:1:c01d:c01a::', 'ffff:ffff:ffff::', ['2001:dead:beef:babe::']), | ||
538 | 601 | ('10.10.0.0/255.255.240.0', None, ['10.10.0.20', '10.10.250.0']), | ||
539 | 487 | ] | 602 | ] |
540 | 488 | 603 | ||
541 | 489 | for ip, mask, test_ip in tests: | 604 | for ip, mask, test_ip in tests: |
542 | @@ -506,4 +621,3 @@ | |||
543 | 506 | print 'last host.:', net.host_last() | 621 | print 'last host.:', net.host_last() |
544 | 507 | for ip in test_ip: | 622 | for ip in test_ip: |
545 | 508 | print '%s in network: ' % ip, ip in net | 623 | print '%s in network: ' % ip, ip in net |
546 | 509 |
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.