Skip to content

Commit 59cf7ec

Browse files
committed
Fixed unbounded list support
1 parent f053df8 commit 59cf7ec

File tree

4 files changed

+162
-56
lines changed

4 files changed

+162
-56
lines changed

src/fedex_python/python/SCL/AggregationDataTypes.py

Lines changed: 82 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -32,37 +32,18 @@
3232
from SimpleDataTypes import *
3333
from TypeChecker import *
3434

35-
class BaseAggregate(object):
36-
""" A class that define common properties to ARRAY, LIST, SET and BAG.
35+
def type_from_string(type_str):
36+
""" Look for the type definition in the global scope from the type string.
37+
@TODO: find a better implementation than testing all modules!
3738
"""
38-
def __init__( self , bound1 , bound2 , base_type ):
39-
# check that bound1<bound2
40-
if (bound1!=None and bound2!=None):
41-
if bound1>bound2:
42-
raise AssertionError("bound1 shall be less than or equal to bound2")
43-
self._bound1 = bound1
44-
self._bound2 = bound2
45-
self._base_type = base_type
46-
47-
def __getitem__(self, index):
48-
if index<self._bound1:
49-
raise IndexError("ARRAY index out of bound (lower bound is %i, passed %i)"%(self._bound1,index))
50-
elif(self._bound2!=None and index>self._bound2):
51-
raise IndexError("ARRAY index out of bound (upper bound is %i, passed %i)"%(self._bound2,index))
52-
else:
53-
return list.__getitem__(self,index)
54-
55-
def __setitem__(self,index,value):
56-
if index<self._bound1:
57-
raise IndexError("ARRAY index out of bound (lower bound is %i, passed %i)"%(self._bound1,index))
58-
elif (self._bound2!=None and index>self._bound2):
59-
raise IndexError("ARRAY index out of bound (upper bound is %i, passed %i)"%(self._bound2,index))
60-
elif not isinstance(value,self._base_type):
61-
raise TypeError("%s type expected, passed %s."%(self._base_type, type(value)))
62-
else:
63-
# first find the length of the list, and extend it if ever
64-
# the index is
65-
list.__setitem__(self,index,value)
39+
modules = sys.modules
40+
for module in modules.values():
41+
if (module is not None) and (not '__' in module.__name__):
42+
module_variables = vars(module)
43+
if module_variables.has_key(type_str):
44+
typ = module_variables[type_str]
45+
return True, vars(module)[type_str]
46+
return False,None
6647

6748
class ARRAY(object):
6849
"""An array data type has as its domain indexed, fixed-size collections of like elements. The lower
@@ -144,52 +125,97 @@ def __init__( self , bound_1 , bound_2 , base_type , UNIQUE = False):
144125
if not type(bound_1)==int:
145126
raise TypeError("LIST lower bound must be an integer")
146127
# bound_2 can be set to None
147-
if not type(bound_2)==int:
128+
self._unbounded = False
129+
if bound_2 == None:
130+
self._unbounded = True
131+
elif not type(bound_2)==int:
148132
raise TypeError("LIST upper bound must be an integer")
149133
if not bound_1>=0:
150134
raise AssertionError("LIST lower bound must be greater of equal to 0")
151-
if not (bound_1 <= bound_2):
135+
if (type(bound_2)==int and not (bound_1 <= bound_2)):
152136
raise AssertionError("ARRAY lower bound must be less than or equal to upper bound")
153137
# set up class attributes
154138
self._bound_1 = bound_1
155139
self._bound_2 = bound_2
156140
self._base_type = base_type
157141
self._unique = UNIQUE
158-
self._optional = OPTIONAL
159-
# preallocate list elements
160-
list_size = bound_2 - bound_1 + 1
161-
self._container = list_size*[None]
162-
142+
# preallocate list elements if bounds are both integers
143+
if not self._unbounded:
144+
list_size = bound_2 - bound_1 + 1
145+
self._container = list_size*[None]
146+
# for unbounded list, this will come after
147+
else:
148+
self._container = [None]
149+
163150
def bound_1(self):
164151
return self._bound_1
165152

166153
def bound_2(self):
167154
return self._bound_2
168155

169156
def __getitem__(self, index):
170-
if index<self._bound_1:
171-
raise IndexError("ARRAY index out of bound (lower bound is %i, passed %i)"%(self._bound_1,index))
172-
elif(index>self._bound_2):
173-
raise IndexError("ARRAY index out of bound (upper bound is %i, passed %i)"%(self._bound_2,index))
157+
# case bounded
158+
if not self._unbounded:
159+
if index<self._bound_1:
160+
raise IndexError("ARRAY index out of bound (lower bound is %i, passed %i)"%(self._bound_1,index))
161+
elif(index>self._bound_2):
162+
raise IndexError("ARRAY index out of bound (upper bound is %i, passed %i)"%(self._bound_2,index))
163+
else:
164+
value = self._container[index-self._bound_1]
165+
if value == None:
166+
raise AssertionError("Value with index %i not defined. Please set the value first."%index)
167+
return value
168+
#case unbounded
174169
else:
175-
value = self._container[index-self._bound_1]
176-
if not self._optional and value==None:
177-
raise AssertionError("Not OPTIONAL prevent the value with index %i from being None (default). Please set the value first."%index)
178-
return value
170+
if index-self._bound_1>len(self._container):
171+
raise AssertionError("Value with index %i not defined. Please set the value first."%index)
172+
else:
173+
value = self._container[index-self._bound_1]
174+
if value == None:
175+
raise AssertionError("Value with index %i not defined. Please set the value first."%index)
176+
return value
179177

180178
def __setitem__(self, index, value):
181-
if index<self._bound_1:
182-
raise IndexError("ARRAY index out of bound (lower bound is %i, passed %i)"%(self._bound_1,index))
183-
elif(index>self._bound_2):
184-
raise IndexError("ARRAY index out of bound (upper bound is %i, passed %i)"%(self._bound_2,index))
179+
# case bounded
180+
if not self._unbounded:
181+
if index<self._bound_1:
182+
raise IndexError("ARRAY index out of bound (lower bound is %i, passed %i)"%(self._bound_1,index))
183+
elif(index>self._bound_2):
184+
raise IndexError("ARRAY index out of bound (upper bound is %i, passed %i)"%(self._bound_2,index))
185+
else:
186+
# first check the type of the value
187+
check_type(value,self._base_type)
188+
# then check if the value is already in the array
189+
if self._unique:
190+
if value in self._container:
191+
raise AssertionError("UNIQUE keyword prevent inserting this instance.")
192+
self._container[index-self._bound_1] = value
193+
# case unbounded
185194
else:
186-
# first check the type of the value
187-
check_type(value,self._base_type)
188-
# then check if the value is already in the array
189-
if self._unique:
190-
if value in self._container:
191-
raise AssertionError("UNIQUE keyword prevent inserting this instance.")
192-
self._container[index-self._bound_1] = value
195+
if index<self._bound_1:
196+
raise IndexError("ARRAY index out of bound (lower bound is %i, passed %i)"%(self._bound_1,index))
197+
# if the _container list is of good size, just do like the bounded case
198+
if (index-self._bound_1<len(self._container)):
199+
# first check the type of the value
200+
check_type(value,self._base_type)
201+
# then check if the value is already in the array
202+
if self._unique:
203+
if value in self._container:
204+
raise AssertionError("UNIQUE keyword prevent inserting this instance.")
205+
self._container[index-self._bound_1] = value
206+
# in the other case, we have to extend the base _container list
207+
else:
208+
delta_size = (index-self._bound_1) - len(self._container) + 1
209+
#create a list of None, and extend the list
210+
list_extension = delta_size*[None]
211+
self._container.extend(list_extension)
212+
# first check the type of the value
213+
check_type(value,self._base_type)
214+
# then check if the value is already in the array
215+
if self._unique:
216+
if value in self._container:
217+
raise AssertionError("UNIQUE keyword prevent inserting this instance.")
218+
self._container[index-self._bound_1] = value
193219

194220
class BAG(tuple, BaseAggregate):
195221
"""A bag data type has as its domain unordered collections of like elements. The optional lower
-7.63 KB
Binary file not shown.
-320 Bytes
Binary file not shown.

src/fedex_python/python/SCL_unittest.py

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,86 @@ def test_array_optional(self):
217217
b[2] = REAL(5)
218218
b[3] = REAL(5)
219219

220+
#
221+
# AggregationDataTypeSimple
222+
#
223+
class TestLIST(unittest.TestCase):
224+
'''
225+
LIST test
226+
'''
227+
def test_create_bounded_list(self):
228+
LIST(1,7,REAL)
229+
#upper and lower bounds can be negative
230+
LIST(1,5,INTEGER)
231+
# they even can be both 0
232+
LIST(0,0,REAL)
233+
LIST(1,1,BOOLEAN)
234+
# lower bound should be less or equal than upper bound
235+
try:
236+
LIST(3,2,REAL)
237+
except AssertionError:
238+
pass
239+
except e:
240+
self.fail('Unexpected exception thrown:', e)
241+
else:
242+
self.fail('ExpectedException not thrown')
243+
# lower bound should be greater or equal than zero
244+
try:
245+
LIST(-1,2,REAL)
246+
except AssertionError:
247+
pass
248+
except e:
249+
self.fail('Unexpected exception thrown:', e)
250+
else:
251+
self.fail('ExpectedException not thrown')
252+
253+
def test_create_unbounded_list(self):
254+
a = LIST(0,None,REAL)
255+
a[6] = REAL(6)
256+
self.assertEqual(a[6],6)
257+
b = LIST(10,None,REAL)
258+
a[10] = REAL(7)
259+
self.assertEqual(a[10],7)
260+
261+
def test_list_bounds(self):
262+
a = LIST(3,8,REAL)
263+
try:
264+
a[2]
265+
except IndexError:
266+
pass
267+
except e:
268+
self.fail('Unexpected exception thrown:', e)
269+
else:
270+
self.fail('ExpectedException not thrown')
271+
try:
272+
a[9]
273+
except IndexError:
274+
pass
275+
except e:
276+
self.fail('Unexpected exception thrown:', e)
277+
else:
278+
self.fail('ExpectedException not thrown')
279+
280+
def test_list_unique(self):
281+
# if UNIQUE is not set to True (False by default),
282+
# the array may contain the same instance at different
283+
# positions
284+
a = LIST(1,4,REAL)
285+
a[3] = REAL(4)
286+
a[4] = REAL(4)
287+
# however, if UNIQUE, then every instances in the
288+
# array must be different
289+
a = LIST(1,4,REAL,UNIQUE=True)
290+
a[3] = REAL(4)
291+
try:
292+
a[3] = REAL(4)
293+
except AssertionError:
294+
pass
295+
except e:
296+
self.fail('Unexpected exception thrown:', e)
297+
else:
298+
self.fail('ExpectedException not thrown')
299+
220300
#
221301
# TypeChecker
222302
#

0 commit comments

Comments
 (0)