Improved NumberRange handling

This commit is contained in:
Konsta Vesterinen
2014-01-05 05:28:58 +02:00
parent 932391f1ca
commit 1d7a27413f
3 changed files with 68 additions and 17 deletions

View File

@@ -65,7 +65,8 @@ class NumberRange(object):
def lower(self, value):
if value is None:
self._lower = -float('inf')
self._lower = value
else:
self._lower = value
@property
def upper(self):
@@ -75,7 +76,22 @@ class NumberRange(object):
def upper(self, value):
if value is None:
self._upper = float('inf')
self._upper = value
else:
self._upper = value
@property
def open(self):
"""
Returns whether or not this object is an open interval.
"""
return not self.lower_inc and not self.upper_inc
@property
def closed(self):
"""
Returns whether or not this object is a closed interval.
"""
return self.lower_inc and self.upper_inc
def parse_object(self, obj):
self.lower = obj.lower
@@ -93,7 +109,10 @@ class NumberRange(object):
lower, upper = seq
self.lower = parse_number(lower)
self.upper = parse_number(upper)
self.lower_inc = self.upper_inc = True
if isinstance(seq, tuple):
self.lower_inc = self.upper_inc = False
else:
self.lower_inc = self.upper_inc = True
def parse_integer(self, value):
self.lower = self.upper = value
@@ -125,14 +144,8 @@ class NumberRange(object):
except ValueError as e:
raise NumberRangeException(e.message)
self.lower_inc = value[0] == '('
if self.lower_inc:
lower += 1
self.upper_inc = value[-1] == ')'
if self.upper_inc:
upper -= 1
self.lower_inc = value[0] == '['
self.upper_inc = value[-1] == ']'
self.lower = lower
self.upper = upper
@@ -151,9 +164,11 @@ class NumberRange(object):
@property
def normalized(self):
return '[%s, %s]' % (
self.lower if self.lower is not None else '',
self.upper if self.upper is not None else ''
return '%s%s, %s%s' % (
'[' if self.lower_inc else '(',
self.lower if self.lower != -float('inf') else '',
self.upper if self.upper != float('inf') else '',
']' if self.upper_inc else ')'
)
def __eq__(self, other):

View File

@@ -30,6 +30,11 @@ class TestNumberRangeInit(object):
assert num_range.lower == 1
assert num_range.upper == 3
def test_empty_string_as_upper_bound(self):
num_range = NumberRange('[1,)')
assert num_range.lower == 1
assert num_range.upper == float('inf')
def test_supports_exact_ranges_as_strings(self):
num_range = NumberRange('3')
assert num_range.lower == 3
@@ -93,6 +98,36 @@ def test_raises_exception_for_badly_constructed_range(number_range):
NumberRange(number_range)
@mark.parametrize(('number_range', 'is_open'),
(
((2, 3), True),
('(2, 5)', True),
('[3, 4)', False),
('(4, 5]', False),
('3 - 4', False),
([4, 5], False),
('[4, 5]', False)
)
)
def test_open(number_range, is_open):
assert NumberRange(number_range).open == is_open
@mark.parametrize(('number_range', 'is_closed'),
(
((2, 3), False),
('(2, 5)', False),
('[3, 4)', False),
('(4, 5]', False),
('3 - 4', True),
([4, 5], True),
('[4, 5]', True)
)
)
def test_closed(number_range, is_closed):
assert NumberRange(number_range).closed == is_closed
class TestArithmeticOperators(object):
def test_add_operator(self):
assert NumberRange(1, 2) + NumberRange(1, 2) == NumberRange(2, 4)

View File

@@ -36,9 +36,10 @@ class TestNumberRangeType(TestCase):
)
self.session.add(building)
self.session.commit()
building = self.session.query(self.Building).first()
assert building.persons_at_night.lower == 1
assert building.persons_at_night.upper is None
assert building.persons_at_night.upper == float('inf')
def test_infinite_lower_bound(self):
building = self.Building(
@@ -47,8 +48,8 @@ class TestNumberRangeType(TestCase):
self.session.add(building)
self.session.commit()
building = self.session.query(self.Building).first()
assert building.persons_at_night.lower is None
assert building.persons_at_night.upper is 1
assert building.persons_at_night.lower == -float('inf')
assert building.persons_at_night.upper == 1
def test_nullify_number_range(self):
building = self.Building(