diff --git a/.travis.yml b/.travis.yml index 5d1228b..1da4d2c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,11 +1,25 @@ language: python -python: - - 2.7 - - 3.3 - - 3.4 - - 3.5 - - pypy - - pypy3 +matrix: + include: + - python: 2.7 + dist: trusty + sudo: false + - python: 3.3 + dist: trusty + sudo: false + - python: 3.4 + dist: trusty + sudo: false + - python: 3.5 + dist: trusty + sudo: false + - python: pypy + dist: trusty + sudo: false + - python: pypy3 + dist: trusty + sudo: false + install: - pip install -e ".[test]" script: diff --git a/intervals/interval.py b/intervals/interval.py index 0e3ad96..228d4d0 100644 --- a/intervals/interval.py +++ b/intervals/interval.py @@ -184,15 +184,19 @@ def __init__( self.parser(bounds, lower_inc, upper_inc) ) - if self.lower > self.upper: + self.range_init_and_setter_exception_detect(self.lower, self.upper, self.lower_inc, self.upper_inc) + + @classmethod + def range_init_and_setter_exception_detect(cls, lower, upper, lower_inc, upper_inc): + if lower > upper: raise RangeBoundsException( - self.lower, - self.upper + lower, + upper ) if ( - self.lower == self.upper and - not self.lower_inc and - not self.upper_inc + lower == upper and + not lower_inc and + not upper_inc ): raise IllegalArgument( 'The bounds may be equal only if at least one of the bounds ' @@ -320,8 +324,13 @@ def lower(self): def lower(self, value): value = self.coerce_value(value) if value is None: + if hasattr(self, 'upper_inc'): + self.range_init_and_setter_exception_detect(-inf, self.upper, self.lower_inc, self.upper_inc) self._lower = -inf else: + if hasattr(self, 'upper_inc'): + self.range_init_and_setter_exception_detect(self.round_value_by_step(value), self.upper, self.lower_inc, + self.upper_inc) self._lower = self.round_value_by_step(value) @property @@ -332,8 +341,13 @@ def upper(self): def upper(self, value): value = self.coerce_value(value) if value is None: + if hasattr(self, 'upper_inc'): + self.range_init_and_setter_exception_detect(self.lower, inf, self.lower_inc, self.upper_inc) self._upper = inf else: + if hasattr(self, 'upper_inc'): + self.range_init_and_setter_exception_detect(self.lower, self.round_value_by_step(value), self.lower_inc, + self.upper_inc) self._upper = self.round_value_by_step(value) def round_value_by_step(self, value): diff --git a/tests/interval/test_initialization.py b/tests/interval/test_initialization.py index c28e582..d75e0be 100644 --- a/tests/interval/test_initialization.py +++ b/tests/interval/test_initialization.py @@ -202,3 +202,47 @@ class TestTypeGuessing(object): ) def test_guesses_types(self, number_range, type): assert Interval(number_range).type == type + + +class TestIntervalChanging(object): + @mark.parametrize( + ('constructor', 'number_range', 'bad_lower'), + ( + (IntInterval, (1, 2), 3), + (IntInterval, [1, 2], 3), + (IntInterval, (1, 2), float('inf')), + (CharacterInterval, ('a', 'b'), 'c'), + (CharacterInterval, ('a', 'b'), 'd'), + (CharacterInterval, ('a', 'b'), inf), + ) + ) + def test_raises_exception_for_badly_lower_changing( + self, + constructor, + number_range, + bad_lower + ): + with raises(RangeBoundsException): + interval = constructor(number_range) + interval.lower = bad_lower + + @mark.parametrize( + ('constructor', 'number_range', 'bad_upper'), + ( + (IntInterval, (1, 2), 0), + (IntInterval, [1, 2], 0), + (IntInterval, (1, 2), float('-inf')), + (CharacterInterval, ('b', 'c'), 'a'), + (CharacterInterval, ('b', 'd'), 'a'), + (CharacterInterval, ('b', 'c'), -inf), + ) + ) + def test_raises_exception_for_badly_upper_changing( + self, + constructor, + number_range, + bad_upper + ): + with raises(RangeBoundsException): + interval = constructor(number_range) + interval.upper = bad_upper