summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLouis des Landes <louis@obsidian.com.au>2013-03-19 16:41:23 +1100
committerLouis des Landes <louis@obsidian.com.au>2013-03-19 16:41:23 +1100
commitf884a6d43ca57f423a8bacb61b2bcbd51bdcbe76 (patch)
tree268bb520f52b28a9cc484fc6ba32f5afc241a3fc
parent328effb64e6dd575d7ba790941261f1efef102ba (diff)
downloadnetaddr-f884a6d43ca57f423a8bacb61b2bcbd51bdcbe76.tar.gz
Add iscontiguous() and getRange() to IPSet
-rw-r--r--netaddr/ip/sets.py31
-rw-r--r--netaddr/tests/2.x/ip/sets.txt22
-rw-r--r--netaddr/tests/3.x/ip/sets.txt21
3 files changed, 74 insertions, 0 deletions
diff --git a/netaddr/ip/sets.py b/netaddr/ip/sets.py
index 0107f74..f928c1b 100644
--- a/netaddr/ip/sets.py
+++ b/netaddr/ip/sets.py
@@ -627,3 +627,34 @@ class IPSet(object):
return 'IPSet(%r)' % [str(c) for c in sorted(self._cidrs)]
__str__ = __repr__
+
+ def iscontiguous(self):
+ """
+ Note this method depends on ``iter_cidrs`` being sorted.
+
+ :return: ``True`` if the ``IPSet`` object is contiguous.
+ """
+ previous = self.iter_cidrs()[0][0]
+ for cidr in self.iter_cidrs():
+ if cidr[0] != previous:
+ # This isn't contiguous
+ return False
+ previous = cidr[-1] + 1
+ return True
+
+ def getRange(self):
+ """
+ Get the starting and ending IP of this set, assuming it is
+ contiguous.
+ Note this method depends on ``iter_cidrs`` being sorted.
+
+ Raises ``ValueError`` if the set is not contiguous.
+
+ :return: An ``IPRange`` if the IPSet is contiguous.
+
+ """
+ if self.iscontiguous():
+ cidrs = self.iter_cidrs()
+ return IPRange(cidrs[0][0], cidrs[-1][-1])
+ else:
+ raise ValueError("IPSet is not contiguous")
diff --git a/netaddr/tests/2.x/ip/sets.txt b/netaddr/tests/2.x/ip/sets.txt
index 661882a..b966300 100644
--- a/netaddr/tests/2.x/ip/sets.txt
+++ b/netaddr/tests/2.x/ip/sets.txt
@@ -437,6 +437,28 @@ And we're back to our original address.
>>> s1
IPSet(['0.0.0.0/0'])
+--------------------------------
+Convert an IP set to an IP Range
+--------------------------------
+Sometimes you may want to convert an IPSet back to an IPRange.
+>>> s1 = IPSet(['10.0.0.0/25', '10.0.0.128/25'])
+
+>>> s1.getRange()
+IPRange('10.0.0.0', '10.0.0.255')
+
+This only works if the IPSet is contiguous
+>>> s1.iscontiguous()
+True
+>>> s1.remove('10.0.0.16')
+>>> s1
+IPSet(['10.0.0.0/28', '10.0.0.17/32', '10.0.0.18/31', '10.0.0.20/30', '10.0.0.24/29', '10.0.0.32/27', '10.0.0.64/26', '10.0.0.128/25'])
+>>> s1.iscontiguous()
+False
+>>> s1.getRange()
+Traceback (most recent call last):
+ File "<stdin>", line 1, in <module>
+ValueError: IPSet is not contiguous
+
----------------------
Pickling IPSet objects
----------------------
diff --git a/netaddr/tests/3.x/ip/sets.txt b/netaddr/tests/3.x/ip/sets.txt
index 07c2548..4c83de7 100644
--- a/netaddr/tests/3.x/ip/sets.txt
+++ b/netaddr/tests/3.x/ip/sets.txt
@@ -485,3 +485,24 @@ Pickling of IPSet objects
True
}}}
+
+Convert an IP set to an IP Range
+
+{{{
+
+>>> s1 = IPSet(['10.0.0.0/25', '10.0.0.128/25'])
+>>> s1.getRange()
+IPRange('10.0.0.0', '10.0.0.255')
+>>> s1.iscontiguous()
+True
+>>> s1.remove('10.0.0.16')
+>>> s1
+IPSet(['10.0.0.0/28', '10.0.0.17/32', '10.0.0.18/31', '10.0.0.20/30', '10.0.0.24/29', '10.0.0.32/27', '10.0.0.64/26', '10.0.0.128/25'])
+>>> s1.iscontiguous()
+False
+>>> s1.getRange()
+Traceback (most recent call last):
+ ...
+ValueError: IPSet is not contiguous
+
+}}}