Preliminary infinity support for number range, refs #48
This commit is contained in:
@@ -19,6 +19,18 @@ class RangeBoundsException(NumberRangeException):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def parse_number(number):
|
||||||
|
if (
|
||||||
|
number == float('inf') or
|
||||||
|
number == -float('inf') or
|
||||||
|
number is None or
|
||||||
|
number == ''
|
||||||
|
):
|
||||||
|
return None
|
||||||
|
else:
|
||||||
|
return int(number)
|
||||||
|
|
||||||
|
|
||||||
@total_ordering
|
@total_ordering
|
||||||
class NumberRange(object):
|
class NumberRange(object):
|
||||||
def __init__(self, *args):
|
def __init__(self, *args):
|
||||||
@@ -30,8 +42,8 @@ class NumberRange(object):
|
|||||||
lower, upper = args
|
lower, upper = args
|
||||||
if lower > upper:
|
if lower > upper:
|
||||||
raise RangeBoundsException(lower, upper)
|
raise RangeBoundsException(lower, upper)
|
||||||
self.lower = lower
|
self.lower = parse_number(lower)
|
||||||
self.upper = upper
|
self.upper = parse_number(upper)
|
||||||
self.lower_inc = self.upper_inc = True
|
self.lower_inc = self.upper_inc = True
|
||||||
else:
|
else:
|
||||||
if isinstance(args[0], six.integer_types):
|
if isinstance(args[0], six.integer_types):
|
||||||
@@ -70,10 +82,10 @@ class NumberRange(object):
|
|||||||
range.lower = 24
|
range.lower = 24
|
||||||
range.upper = 44
|
range.upper = 44
|
||||||
"""
|
"""
|
||||||
values = value[1:-1].split(',')
|
values = value.strip()[1:-1].split(',')
|
||||||
try:
|
try:
|
||||||
lower, upper = map(
|
lower, upper = map(
|
||||||
lambda a: int(a.strip()), values
|
lambda a: parse_number(a.strip()), values
|
||||||
)
|
)
|
||||||
except ValueError as e:
|
except ValueError as e:
|
||||||
raise NumberRangeException(e.message)
|
raise NumberRangeException(e.message)
|
||||||
@@ -93,11 +105,11 @@ class NumberRange(object):
|
|||||||
if value is not None:
|
if value is not None:
|
||||||
values = value.split('-')
|
values = value.split('-')
|
||||||
if len(values) == 1:
|
if len(values) == 1:
|
||||||
lower = upper = int(value.strip())
|
lower = upper = parse_number(value.strip())
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
lower, upper = map(
|
lower, upper = map(
|
||||||
lambda a: int(a.strip()), values
|
lambda a: parse_number(a.strip()), values
|
||||||
)
|
)
|
||||||
except ValueError as e:
|
except ValueError as e:
|
||||||
raise NumberRangeException(str(e))
|
raise NumberRangeException(str(e))
|
||||||
@@ -105,7 +117,10 @@ class NumberRange(object):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def normalized(self):
|
def normalized(self):
|
||||||
return '[%s, %s]' % (self.lower, self.upper)
|
return '[%s, %s]' % (
|
||||||
|
self.lower if self.lower is not None else '',
|
||||||
|
self.upper if self.upper is not None else ''
|
||||||
|
)
|
||||||
|
|
||||||
def __eq__(self, other):
|
def __eq__(self, other):
|
||||||
try:
|
try:
|
||||||
|
@@ -75,11 +75,6 @@ def test_raises_exception_for_badly_constructed_range():
|
|||||||
NumberRange(3, 2)
|
NumberRange(3, 2)
|
||||||
|
|
||||||
|
|
||||||
def test_from_str_exception_handling():
|
|
||||||
with raises(NumberRangeException):
|
|
||||||
NumberRange('1 - ')
|
|
||||||
|
|
||||||
|
|
||||||
class TestArithmeticOperators(object):
|
class TestArithmeticOperators(object):
|
||||||
def test_add_operator(self):
|
def test_add_operator(self):
|
||||||
assert NumberRange(1, 2) + NumberRange(1, 2) == NumberRange(2, 4)
|
assert NumberRange(1, 2) + NumberRange(1, 2) == NumberRange(2, 4)
|
||||||
|
@@ -31,6 +31,16 @@ class TestNumberRangeType(TestCase):
|
|||||||
assert building.persons_at_night.lower == 1
|
assert building.persons_at_night.lower == 1
|
||||||
assert building.persons_at_night.upper == 3
|
assert building.persons_at_night.upper == 3
|
||||||
|
|
||||||
|
def test_infinite_upper_bound(self):
|
||||||
|
building = self.Building(
|
||||||
|
persons_at_night=NumberRange(1, float('inf'))
|
||||||
|
)
|
||||||
|
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
|
||||||
|
|
||||||
def test_nullify_number_range(self):
|
def test_nullify_number_range(self):
|
||||||
building = self.Building(
|
building = self.Building(
|
||||||
persons_at_night=NumberRange(1, 3)
|
persons_at_night=NumberRange(1, 3)
|
||||||
|
Reference in New Issue
Block a user