From 0dd7c159eb7aa05e9c70072c3c2dec3c481aaa26 Mon Sep 17 00:00:00 2001 From: Konsta Vesterinen Date: Tue, 12 Nov 2013 14:35:58 +0200 Subject: [PATCH] Preliminary infinity support for number range, refs #48 --- sqlalchemy_utils/primitives/number_range.py | 29 ++++++++++++++++----- tests/primitives/test_number_range.py | 5 ---- tests/types/test_number_range.py | 10 +++++++ 3 files changed, 32 insertions(+), 12 deletions(-) diff --git a/sqlalchemy_utils/primitives/number_range.py b/sqlalchemy_utils/primitives/number_range.py index 26e9430..d9475f8 100644 --- a/sqlalchemy_utils/primitives/number_range.py +++ b/sqlalchemy_utils/primitives/number_range.py @@ -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 class NumberRange(object): def __init__(self, *args): @@ -30,8 +42,8 @@ class NumberRange(object): lower, upper = args if lower > upper: raise RangeBoundsException(lower, upper) - self.lower = lower - self.upper = upper + self.lower = parse_number(lower) + self.upper = parse_number(upper) self.lower_inc = self.upper_inc = True else: if isinstance(args[0], six.integer_types): @@ -70,10 +82,10 @@ class NumberRange(object): range.lower = 24 range.upper = 44 """ - values = value[1:-1].split(',') + values = value.strip()[1:-1].split(',') try: lower, upper = map( - lambda a: int(a.strip()), values + lambda a: parse_number(a.strip()), values ) except ValueError as e: raise NumberRangeException(e.message) @@ -93,11 +105,11 @@ class NumberRange(object): if value is not None: values = value.split('-') if len(values) == 1: - lower = upper = int(value.strip()) + lower = upper = parse_number(value.strip()) else: try: lower, upper = map( - lambda a: int(a.strip()), values + lambda a: parse_number(a.strip()), values ) except ValueError as e: raise NumberRangeException(str(e)) @@ -105,7 +117,10 @@ class NumberRange(object): @property 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): try: diff --git a/tests/primitives/test_number_range.py b/tests/primitives/test_number_range.py index 982c90f..fd3c73d 100644 --- a/tests/primitives/test_number_range.py +++ b/tests/primitives/test_number_range.py @@ -75,11 +75,6 @@ def test_raises_exception_for_badly_constructed_range(): NumberRange(3, 2) -def test_from_str_exception_handling(): - with raises(NumberRangeException): - NumberRange('1 - ') - - class TestArithmeticOperators(object): def test_add_operator(self): assert NumberRange(1, 2) + NumberRange(1, 2) == NumberRange(2, 4) diff --git a/tests/types/test_number_range.py b/tests/types/test_number_range.py index 3203b96..51ad1a1 100644 --- a/tests/types/test_number_range.py +++ b/tests/types/test_number_range.py @@ -31,6 +31,16 @@ class TestNumberRangeType(TestCase): assert building.persons_at_night.lower == 1 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): building = self.Building( persons_at_night=NumberRange(1, 3)