Swarm-NG  1.1
range_type.py
Go to the documentation of this file.
1 ## @file range_type.py Support routines for the defining ranges to use with queries.
2 
3 ## @package swarmng.range_type
4 # Classes for defining arbitrary ranges easily in Python
5 #
6 
7 import argparse
8 
9 SINGLE, INTERVAL, UNIVERSAL = range(3)
10 ## Simple data structure to specify a range and test against it
11 # This is different from Python range object since it has methods
12 # for testing if a number is in range and also supports infinite ranges.
13 #
14 # To create a Range object: use one of the following static methods:
15 # - Range.single
16 # - Range.interval
17 # - Range.universal
18 #
19 # One of the main uses of Range is to test if it contains a number in the range
20 # @code{.py}
21 # >>> r = Range.interval(5,8)
22 # >>> r.contains(7)
23 # true
24 # >>> r.contains(9)
25 # false
26 # @endcode{.py}
27 #
28 # A range object can be iterated on just like the Python range object
29 # @code{.py}
30 # >>> for i in Range.interval(1,10):
31 # ... print(i)
32 # 1
33 # 2
34 # 3
35 # 4
36 # 5
37 # 6
38 # 7
39 # 8
40 # 9
41 # 10
42 # @endcode
43 # Note that these ranges contain the upper bound.
44 #
45 #
46 # \TODO: make the constructor private
47 class Range:
48  ## Create a range that contains only one number
49  # The upper and lower bound are set to \c s.
50  @staticmethod
51  def single(s):
52  x = Range()
53  x.type = SINGLE
54  x.singleton = s
55  return x
56 
57  ## Create a range from a tuple.
58  # This function can take one tuple as an argument
59  # or two arguments.
60  # @code{.py}
61  # >>> t = (3,8)
62  # >>> Range.interval(t)
63  # >>> Range.interval(10,20)
64  # @endcode
65  @staticmethod
66  def interval(t, u = None):
67  if u != None :
68  tpl = (t,u)
69  else:
70  tpl = t
71 
72  x = Range()
73  x.type = INTERVAL
74  x.interval = t
75  return x
76  ## Create a range that contains everything.
77  # The contain method for this object always returns true.
78  # The upper and lower for this object are undefined.
79  @staticmethod
80  def universal():
81  x = Range()
82  x.type = UNIVERSAL
83  return x
84 
85  def isInterval(self):
86  return self.type == INTERVAL
87  def isSingle(self):
88  return self.type == SINGLE
89  def isUniversal(self):
90  return self.type == UNIVERSAL
91 
92 
93  ## Test that the range contains the number \c i
94  def contains(self,i):
95  if(self.type == SINGLE):
96  return i == self.singleton
97  elif(self.type == INTERVAL):
98  a,b = self.interval
99  return a <= i <= b
100  elif(self.type == UNIVERSAL):
101  return True
102 
103  ## Create an iterator limiting this range to lower and upper.
104  # this is very useful for cases where UNIVERSAL ranges are
105  # allowed, because the UNIVERSAL range will be clamped to
106  # the provided lower and uppper bound.
107  def with_limits(self,lower,upper):
108  if(self.type == SINGLE):
109  if(lower <= self.single <= upper):
110  yield self.singleton
111  elif(self.type == INTERVAL):
112  a,b = self.interval
113  for i in range(max(a,lower),min(upper,b)+1):
114  yield i
115  else:
116  for i in range(lower,upper+1):
117  yield i
118 
119 
120 
121  def __iter__(self):
122  if(self.type == SINGLE):
123  yield self.singleton
124  elif(self.type == INTERVAL):
125  a,b = self.interval
126  for i in range(a,b+1):
127  yield i
128  else:
129  raise StopIteration
130 
131  ## Lower bound for the range.
132  # WARNING it is undefined for Universal range type.
133  def lower(self):
134  if(self.type == SINGLE):
135  return self.singleton
136  elif(self.type == INTERVAL):
137  return self.interval[0]
138  else:
139  raise ArgumentError
140 
141  ## Upper bound for the range.
142  # WARNING it is undefined for Universal range type.
143  def upper(self):
144  if(self.type == SINGLE):
145  return self.singleton
146  elif(self.type == INTERVAL):
147  return self.interval[1]
148  else:
149  raise ArgumentError
150 
151  ## Lower/Upper bound as a tuple.
152  # WARNING it is undefined for Universal range type.
153  def ulPair(self):
154  if(self.type == SINGLE):
155  return (self.singleton,self.singleton)
156  elif(self.type == INTERVAL):
157  return self.interval
158  else:
159  raise ArgumentError
160 
161  def __repr__(self):
162  if(self.type == SINGLE):
163  return "[ " + repr(self.singleton) + "]"
164  elif(self.type == INTERVAL):
165  a,b = self.interval
166  return "[ " + repr(a) + ".." + repr(b) + "]"
167  elif(self.type == UNIVERSAL):
168  return "[ .. ]"
169 
170 class RangeType(object):
171  def __init__(self,type=int):
172  self.type = type
173  def __call__(self, string):
174  x = string.split("..")
175  if (len(x) == 2):
176  return Range.interval((self.type(x[0]),self.type(x[1])))
177  elif( len(x) == 1):
178  return Range.single(self.type(x[0]))
179  else:
180  raise argparse.ArgumentTypeError("Invalid range '%s' valid range should be like '1..2'" % string)