From c620de32ce73d6096178581d7036cbade155f308 Mon Sep 17 00:00:00 2001 From: easybase Date: Mon, 20 Jan 2020 20:29:55 +0800 Subject: [PATCH 01/11] fix: Range error of modifying the lower and the upper property on an exist interval instance. before fixing: IntInterval('[1, 2]') >>> interval.lower = 3 >>> interval IntInterval('[3, 2]') after fixing: --- intervals/interval.py | 80 ++++++++++++--------- tests/interval/test_initialization.py | 100 ++++++++++++++++++-------- 2 files changed, 120 insertions(+), 60 deletions(-) diff --git a/intervals/interval.py b/intervals/interval.py index 0e3ad96..f0e25af 100644 --- a/intervals/interval.py +++ b/intervals/interval.py @@ -40,9 +40,9 @@ def py2round(value): Python 3 also returns an int; Python 2 returns a float. """ if value > 0: - return float(floor(float(value)+0.5)) + return float(floor(float(value) + 0.5)) else: - return float(ceil(float(value)-0.5)) + return float(ceil(float(value) - 0.5)) def canonicalize_lower(interval, inc=True): @@ -86,11 +86,11 @@ def canonicalize(interval, lower_inc=True, upper_inc=False): def coerce_interval(func): def wrapper(self, arg): if ( - isinstance(arg, list) or - isinstance(arg, tuple) or - isinstance(arg, self.type) or - isinstance(arg, type(self)) or - arg == inf or arg == -inf + isinstance(arg, list) or + isinstance(arg, tuple) or + isinstance(arg, self.type) or + isinstance(arg, type(self)) or + arg == inf or arg == -inf ): try: if arg is not None: @@ -103,6 +103,7 @@ def wrapper(self, arg): except (ValueError, TypeError): pass return func(self, arg) + return wrapper @@ -112,11 +113,11 @@ class AbstractInterval(object): parser = IntervalParser() def __init__( - self, - bounds, - lower_inc=None, - upper_inc=None, - step=None + self, + bounds, + lower_inc=None, + upper_inc=None, + step=None ): """ Parse given args and assign lower and upper bound for this number @@ -184,15 +185,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 +325,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 +342,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): @@ -385,11 +400,11 @@ def __str__(self): def equals(self, other): return ( - self.lower == other.lower and - self.upper == other.upper and - self.lower_inc == other.lower_inc and - self.upper_inc == other.upper_inc and - self.type == other.type + self.lower == other.lower and + self.upper == other.upper and + self.lower_inc == other.lower_inc and + self.upper_inc == other.upper_inc and + self.type == other.type ) @coerce_interval @@ -443,8 +458,8 @@ def __contains__(self, other): else operator.gt ) return ( - lower_op(self.lower, other.lower) and - upper_op(self.upper, other.upper) + lower_op(self.lower, other.lower) and + upper_op(self.upper, other.upper) ) @property @@ -476,12 +491,12 @@ def degenerate(self): def empty(self): if self.discrete and not self.degenerate: return ( - self.upper - self.lower == self.step - and not (self.upper_inc or self.lower_inc) + self.upper - self.lower == self.step + and not (self.upper_inc or self.lower_inc) ) return ( - self.upper == self.lower - and not (self.lower_inc and self.upper_inc) + self.upper == self.lower + and not (self.lower_inc and self.upper_inc) ) def __bool__(self): @@ -672,10 +687,10 @@ def is_connected(self, other): * [1, 3) and (3, 5) are not connected """ return self.upper > other.lower and other.upper > self.lower or ( - self.upper == other.lower and (self.upper_inc or other.lower_inc) + self.upper == other.lower and (self.upper_inc or other.lower_inc) ) or ( - self.lower == other.upper and (self.lower_inc or other.upper_inc) - ) + self.lower == other.upper and (self.lower_inc or other.upper_inc) + ) class NumberInterval(AbstractInterval): @@ -792,4 +807,5 @@ def from_string(self, value): 'Could not initialize interval.' ) + Interval = IntervalFactory() diff --git a/tests/interval/test_initialization.py b/tests/interval/test_initialization.py index c28e582..f911df2 100644 --- a/tests/interval/test_initialization.py +++ b/tests/interval/test_initialization.py @@ -20,18 +20,18 @@ def test_string_as_constructor_param(self): with raises(TypeError) as e: FloatInterval('(0.2, 0.5)') assert ( - 'First argument should be a list or tuple. If you wish to ' - 'initialize an interval from string, use from_string factory ' - 'method.' - ) in str(e) + 'First argument should be a list or tuple. If you wish to ' + 'initialize an interval from string, use from_string factory ' + 'method.' + ) in str(e) def test_invalid_argument(self): with raises(IllegalArgument) as e: FloatInterval((0, 0)) assert ( - 'The bounds may be equal only if at least one of the bounds is ' - 'closed.' - ) in str(e) + 'The bounds may be equal only if at least one of the bounds is ' + 'closed.' + ) in str(e) def test_floats(self): interval = FloatInterval((0.2, 0.5)) @@ -155,11 +155,11 @@ def test_empty_string_as_lower_bound_for_char_interval(self): @mark.parametrize( ('number_range', 'lower', 'upper'), ( - ('-2-2', -2, 2), - ('-3--2', -3, -2), - ('2-3', 2, 3), - ('2-', 2, inf), - ('-5', -5, -5) + ('-2-2', -2, 2), + ('-3--2', -3, -2), + ('2-3', 2, 3), + ('2-', 2, inf), + ('-5', -5, -5) ) ) def test_hyphen_format(self, number_range, lower, upper): @@ -170,18 +170,18 @@ def test_hyphen_format(self, number_range, lower, upper): @mark.parametrize( ('constructor', 'number_range'), ( - (IntInterval, (3, 2)), - (IntInterval, [4, 2]), - (IntInterval, (float('inf'), 2)), - (CharacterInterval, ('c', 'b')), - (CharacterInterval, ('d', 'b')), - (CharacterInterval, (inf, 'b')), + (IntInterval, (3, 2)), + (IntInterval, [4, 2]), + (IntInterval, (float('inf'), 2)), + (CharacterInterval, ('c', 'b')), + (CharacterInterval, ('d', 'b')), + (CharacterInterval, (inf, 'b')), ) ) def test_raises_exception_for_badly_constructed_range( - self, - constructor, - number_range + self, + constructor, + number_range ): with raises(RangeBoundsException): constructor(number_range) @@ -191,14 +191,58 @@ class TestTypeGuessing(object): @mark.parametrize( ('number_range', 'type'), ( - ((2, 3), int), - ([-6, 8], int), - (8.5, float), - ([Decimal(2), 9], int), - ([Decimal('0.5'), 9], float), - ([date(2000, 1, 1), inf], date), - (('a', 'e'), str), + ((2, 3), int), + ([-6, 8], int), + (8.5, float), + ([Decimal(2), 9], int), + ([Decimal('0.5'), 9], float), + ([date(2000, 1, 1), inf], date), + (('a', 'e'), str), ) ) 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 From 351f8b69c9bc7d08694aeb473b7a728ee7ee5bad Mon Sep 17 00:00:00 2001 From: easybase Date: Mon, 20 Jan 2020 20:29:55 +0800 Subject: [PATCH 02/11] fix: Range error of modifying the lower and the upper property on an exist interval instance. before fixing: >>> interval = IntInterval([1, 2]) >>> interval IntInterval('[1, 2]') >>> interval.lower = 3 >>> interval IntInterval('[3, 2]') after fixing: >>> interval = IntInterval([1, 2]) >>> interval IntInterval('[1, 2]') >>> interval.lower = 3 >>> interval it will raise the RangeBoundsException: intervals.exc.RangeBoundsException: Min value 3 is bigger than max value 2. --- .idea/vcs.xml | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 .idea/vcs.xml diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file From 47df2a3c75f3cc9a53acd024b002737b4ae70d2b Mon Sep 17 00:00:00 2001 From: easybase <57800318+easybase@users.noreply.github.com> Date: Mon, 20 Jan 2020 21:19:56 +0800 Subject: [PATCH 03/11] Delete vcs.xml --- .idea/vcs.xml | 6 ------ 1 file changed, 6 deletions(-) delete mode 100644 .idea/vcs.xml diff --git a/.idea/vcs.xml b/.idea/vcs.xml deleted file mode 100644 index 94a25f7..0000000 --- a/.idea/vcs.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file From f0fd97b3384cc3f81ee4eb68ae13a38e20be92af Mon Sep 17 00:00:00 2001 From: easybase <57800318+easybase@users.noreply.github.com> Date: Mon, 20 Jan 2020 20:29:55 +0800 Subject: [PATCH 04/11] fix: Range error of modifying the lower and the upper property on an exist interval instance. before fixing: IntInterval('[1, 2]') >>> interval.lower = 3 >>> interval IntInterval('[3, 2]') after fixing: >>> interval = IntInterval([1, 2]) >>> interval IntInterval('[1, 2]') >>> interval.lower = 3 >>> interval it will raise the RangeBoundsException: intervals.exc.RangeBoundsException: Min value 3 is bigger than max value 2. --- .idea/vcs.xml | 6 ++ intervals/interval.py | 80 ++++++++++++--------- tests/interval/test_initialization.py | 100 ++++++++++++++++++-------- 3 files changed, 126 insertions(+), 60 deletions(-) create mode 100644 .idea/vcs.xml diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/intervals/interval.py b/intervals/interval.py index 0e3ad96..f0e25af 100644 --- a/intervals/interval.py +++ b/intervals/interval.py @@ -40,9 +40,9 @@ def py2round(value): Python 3 also returns an int; Python 2 returns a float. """ if value > 0: - return float(floor(float(value)+0.5)) + return float(floor(float(value) + 0.5)) else: - return float(ceil(float(value)-0.5)) + return float(ceil(float(value) - 0.5)) def canonicalize_lower(interval, inc=True): @@ -86,11 +86,11 @@ def canonicalize(interval, lower_inc=True, upper_inc=False): def coerce_interval(func): def wrapper(self, arg): if ( - isinstance(arg, list) or - isinstance(arg, tuple) or - isinstance(arg, self.type) or - isinstance(arg, type(self)) or - arg == inf or arg == -inf + isinstance(arg, list) or + isinstance(arg, tuple) or + isinstance(arg, self.type) or + isinstance(arg, type(self)) or + arg == inf or arg == -inf ): try: if arg is not None: @@ -103,6 +103,7 @@ def wrapper(self, arg): except (ValueError, TypeError): pass return func(self, arg) + return wrapper @@ -112,11 +113,11 @@ class AbstractInterval(object): parser = IntervalParser() def __init__( - self, - bounds, - lower_inc=None, - upper_inc=None, - step=None + self, + bounds, + lower_inc=None, + upper_inc=None, + step=None ): """ Parse given args and assign lower and upper bound for this number @@ -184,15 +185,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 +325,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 +342,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): @@ -385,11 +400,11 @@ def __str__(self): def equals(self, other): return ( - self.lower == other.lower and - self.upper == other.upper and - self.lower_inc == other.lower_inc and - self.upper_inc == other.upper_inc and - self.type == other.type + self.lower == other.lower and + self.upper == other.upper and + self.lower_inc == other.lower_inc and + self.upper_inc == other.upper_inc and + self.type == other.type ) @coerce_interval @@ -443,8 +458,8 @@ def __contains__(self, other): else operator.gt ) return ( - lower_op(self.lower, other.lower) and - upper_op(self.upper, other.upper) + lower_op(self.lower, other.lower) and + upper_op(self.upper, other.upper) ) @property @@ -476,12 +491,12 @@ def degenerate(self): def empty(self): if self.discrete and not self.degenerate: return ( - self.upper - self.lower == self.step - and not (self.upper_inc or self.lower_inc) + self.upper - self.lower == self.step + and not (self.upper_inc or self.lower_inc) ) return ( - self.upper == self.lower - and not (self.lower_inc and self.upper_inc) + self.upper == self.lower + and not (self.lower_inc and self.upper_inc) ) def __bool__(self): @@ -672,10 +687,10 @@ def is_connected(self, other): * [1, 3) and (3, 5) are not connected """ return self.upper > other.lower and other.upper > self.lower or ( - self.upper == other.lower and (self.upper_inc or other.lower_inc) + self.upper == other.lower and (self.upper_inc or other.lower_inc) ) or ( - self.lower == other.upper and (self.lower_inc or other.upper_inc) - ) + self.lower == other.upper and (self.lower_inc or other.upper_inc) + ) class NumberInterval(AbstractInterval): @@ -792,4 +807,5 @@ def from_string(self, value): 'Could not initialize interval.' ) + Interval = IntervalFactory() diff --git a/tests/interval/test_initialization.py b/tests/interval/test_initialization.py index c28e582..f911df2 100644 --- a/tests/interval/test_initialization.py +++ b/tests/interval/test_initialization.py @@ -20,18 +20,18 @@ def test_string_as_constructor_param(self): with raises(TypeError) as e: FloatInterval('(0.2, 0.5)') assert ( - 'First argument should be a list or tuple. If you wish to ' - 'initialize an interval from string, use from_string factory ' - 'method.' - ) in str(e) + 'First argument should be a list or tuple. If you wish to ' + 'initialize an interval from string, use from_string factory ' + 'method.' + ) in str(e) def test_invalid_argument(self): with raises(IllegalArgument) as e: FloatInterval((0, 0)) assert ( - 'The bounds may be equal only if at least one of the bounds is ' - 'closed.' - ) in str(e) + 'The bounds may be equal only if at least one of the bounds is ' + 'closed.' + ) in str(e) def test_floats(self): interval = FloatInterval((0.2, 0.5)) @@ -155,11 +155,11 @@ def test_empty_string_as_lower_bound_for_char_interval(self): @mark.parametrize( ('number_range', 'lower', 'upper'), ( - ('-2-2', -2, 2), - ('-3--2', -3, -2), - ('2-3', 2, 3), - ('2-', 2, inf), - ('-5', -5, -5) + ('-2-2', -2, 2), + ('-3--2', -3, -2), + ('2-3', 2, 3), + ('2-', 2, inf), + ('-5', -5, -5) ) ) def test_hyphen_format(self, number_range, lower, upper): @@ -170,18 +170,18 @@ def test_hyphen_format(self, number_range, lower, upper): @mark.parametrize( ('constructor', 'number_range'), ( - (IntInterval, (3, 2)), - (IntInterval, [4, 2]), - (IntInterval, (float('inf'), 2)), - (CharacterInterval, ('c', 'b')), - (CharacterInterval, ('d', 'b')), - (CharacterInterval, (inf, 'b')), + (IntInterval, (3, 2)), + (IntInterval, [4, 2]), + (IntInterval, (float('inf'), 2)), + (CharacterInterval, ('c', 'b')), + (CharacterInterval, ('d', 'b')), + (CharacterInterval, (inf, 'b')), ) ) def test_raises_exception_for_badly_constructed_range( - self, - constructor, - number_range + self, + constructor, + number_range ): with raises(RangeBoundsException): constructor(number_range) @@ -191,14 +191,58 @@ class TestTypeGuessing(object): @mark.parametrize( ('number_range', 'type'), ( - ((2, 3), int), - ([-6, 8], int), - (8.5, float), - ([Decimal(2), 9], int), - ([Decimal('0.5'), 9], float), - ([date(2000, 1, 1), inf], date), - (('a', 'e'), str), + ((2, 3), int), + ([-6, 8], int), + (8.5, float), + ([Decimal(2), 9], int), + ([Decimal('0.5'), 9], float), + ([date(2000, 1, 1), inf], date), + (('a', 'e'), str), ) ) 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 From 1fe9602b8eb82a6c9a2affd08753e14091607712 Mon Sep 17 00:00:00 2001 From: easybase <57800318+easybase@users.noreply.github.com> Date: Mon, 20 Jan 2020 21:52:12 +0800 Subject: [PATCH 05/11] Delete vcs.xml --- .idea/vcs.xml | 6 ------ 1 file changed, 6 deletions(-) delete mode 100644 .idea/vcs.xml diff --git a/.idea/vcs.xml b/.idea/vcs.xml deleted file mode 100644 index 94a25f7..0000000 --- a/.idea/vcs.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file From a5531a41f67385ec990e47b13851c59a585a5d78 Mon Sep 17 00:00:00 2001 From: easybase <57800318+easybase@users.noreply.github.com> Date: Mon, 20 Jan 2020 22:49:31 +0800 Subject: [PATCH 06/11] Update .travis.yml --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 5d1228b..6ba6ab9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,6 +2,7 @@ language: python python: - 2.7 - 3.3 + dist:trusty - 3.4 - 3.5 - pypy From 98db8a137b6d5e9714a9fdbd8d7d120a40d56a4d Mon Sep 17 00:00:00 2001 From: easybase <57800318+easybase@users.noreply.github.com> Date: Mon, 20 Jan 2020 22:52:07 +0800 Subject: [PATCH 07/11] Update .travis.yml --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 6ba6ab9..5d1228b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,7 +2,6 @@ language: python python: - 2.7 - 3.3 - dist:trusty - 3.4 - 3.5 - pypy From d87d03d377515d23244f79e1ba9a5017fb397c68 Mon Sep 17 00:00:00 2001 From: easybase <57800318+easybase@users.noreply.github.com> Date: Mon, 20 Jan 2020 22:59:21 +0800 Subject: [PATCH 08/11] Update .travis.yml --- .travis.yml | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) 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: From 8b82b083dda76cd2ccfc91837024dc2fb9a44c17 Mon Sep 17 00:00:00 2001 From: easybase Date: Thu, 23 Jan 2020 11:11:55 +0800 Subject: [PATCH 09/11] fix: Range error detection when modify the lower or the upper property on an exist interval instance. before fixing: >>> interval = IntInterval([1, 2]) >>> interval IntInterval('[1, 2]') >>> interval.lower = 3 >>> interval IntInterval('[3, 2]') after fixing: >>> interval = IntInterval([1, 2]) >>> interval IntInterval('[1, 2]') >>> interval.lower = 3 >>> interval it will raise the RangeBoundsException: intervals.exc.RangeBoundsException: Min value 3 is bigger than max value 2. --- intervals/interval.py | 54 +++++++++--------- tests/interval/test_initialization.py | 80 +++++++++++++-------------- 2 files changed, 66 insertions(+), 68 deletions(-) diff --git a/intervals/interval.py b/intervals/interval.py index f0e25af..f6808e1 100644 --- a/intervals/interval.py +++ b/intervals/interval.py @@ -40,9 +40,9 @@ def py2round(value): Python 3 also returns an int; Python 2 returns a float. """ if value > 0: - return float(floor(float(value) + 0.5)) + return float(floor(float(value)+0.5)) else: - return float(ceil(float(value) - 0.5)) + return float(ceil(float(value)-0.5)) def canonicalize_lower(interval, inc=True): @@ -86,11 +86,11 @@ def canonicalize(interval, lower_inc=True, upper_inc=False): def coerce_interval(func): def wrapper(self, arg): if ( - isinstance(arg, list) or - isinstance(arg, tuple) or - isinstance(arg, self.type) or - isinstance(arg, type(self)) or - arg == inf or arg == -inf + isinstance(arg, list) or + isinstance(arg, tuple) or + isinstance(arg, self.type) or + isinstance(arg, type(self)) or + arg == inf or arg == -inf ): try: if arg is not None: @@ -103,7 +103,6 @@ def wrapper(self, arg): except (ValueError, TypeError): pass return func(self, arg) - return wrapper @@ -113,11 +112,11 @@ class AbstractInterval(object): parser = IntervalParser() def __init__( - self, - bounds, - lower_inc=None, - upper_inc=None, - step=None + self, + bounds, + lower_inc=None, + upper_inc=None, + step=None ): """ Parse given args and assign lower and upper bound for this number @@ -400,11 +399,11 @@ def __str__(self): def equals(self, other): return ( - self.lower == other.lower and - self.upper == other.upper and - self.lower_inc == other.lower_inc and - self.upper_inc == other.upper_inc and - self.type == other.type + self.lower == other.lower and + self.upper == other.upper and + self.lower_inc == other.lower_inc and + self.upper_inc == other.upper_inc and + self.type == other.type ) @coerce_interval @@ -458,8 +457,8 @@ def __contains__(self, other): else operator.gt ) return ( - lower_op(self.lower, other.lower) and - upper_op(self.upper, other.upper) + lower_op(self.lower, other.lower) and + upper_op(self.upper, other.upper) ) @property @@ -491,12 +490,12 @@ def degenerate(self): def empty(self): if self.discrete and not self.degenerate: return ( - self.upper - self.lower == self.step - and not (self.upper_inc or self.lower_inc) + self.upper - self.lower == self.step + and not (self.upper_inc or self.lower_inc) ) return ( - self.upper == self.lower - and not (self.lower_inc and self.upper_inc) + self.upper == self.lower + and not (self.lower_inc and self.upper_inc) ) def __bool__(self): @@ -687,10 +686,10 @@ def is_connected(self, other): * [1, 3) and (3, 5) are not connected """ return self.upper > other.lower and other.upper > self.lower or ( - self.upper == other.lower and (self.upper_inc or other.lower_inc) + self.upper == other.lower and (self.upper_inc or other.lower_inc) ) or ( - self.lower == other.upper and (self.lower_inc or other.upper_inc) - ) + self.lower == other.upper and (self.lower_inc or other.upper_inc) + ) class NumberInterval(AbstractInterval): @@ -807,5 +806,4 @@ def from_string(self, value): 'Could not initialize interval.' ) - Interval = IntervalFactory() diff --git a/tests/interval/test_initialization.py b/tests/interval/test_initialization.py index f911df2..0ae9680 100644 --- a/tests/interval/test_initialization.py +++ b/tests/interval/test_initialization.py @@ -20,18 +20,18 @@ def test_string_as_constructor_param(self): with raises(TypeError) as e: FloatInterval('(0.2, 0.5)') assert ( - 'First argument should be a list or tuple. If you wish to ' - 'initialize an interval from string, use from_string factory ' - 'method.' - ) in str(e) + 'First argument should be a list or tuple. If you wish to ' + 'initialize an interval from string, use from_string factory ' + 'method.' + ) in str(e) def test_invalid_argument(self): with raises(IllegalArgument) as e: FloatInterval((0, 0)) assert ( - 'The bounds may be equal only if at least one of the bounds is ' - 'closed.' - ) in str(e) + 'The bounds may be equal only if at least one of the bounds is ' + 'closed.' + ) in str(e) def test_floats(self): interval = FloatInterval((0.2, 0.5)) @@ -155,11 +155,11 @@ def test_empty_string_as_lower_bound_for_char_interval(self): @mark.parametrize( ('number_range', 'lower', 'upper'), ( - ('-2-2', -2, 2), - ('-3--2', -3, -2), - ('2-3', 2, 3), - ('2-', 2, inf), - ('-5', -5, -5) + ('-2-2', -2, 2), + ('-3--2', -3, -2), + ('2-3', 2, 3), + ('2-', 2, inf), + ('-5', -5, -5) ) ) def test_hyphen_format(self, number_range, lower, upper): @@ -170,18 +170,18 @@ def test_hyphen_format(self, number_range, lower, upper): @mark.parametrize( ('constructor', 'number_range'), ( - (IntInterval, (3, 2)), - (IntInterval, [4, 2]), - (IntInterval, (float('inf'), 2)), - (CharacterInterval, ('c', 'b')), - (CharacterInterval, ('d', 'b')), - (CharacterInterval, (inf, 'b')), + (IntInterval, (3, 2)), + (IntInterval, [4, 2]), + (IntInterval, (float('inf'), 2)), + (CharacterInterval, ('c', 'b')), + (CharacterInterval, ('d', 'b')), + (CharacterInterval, (inf, 'b')), ) ) def test_raises_exception_for_badly_constructed_range( - self, - constructor, - number_range + self, + constructor, + number_range ): with raises(RangeBoundsException): constructor(number_range) @@ -191,13 +191,13 @@ class TestTypeGuessing(object): @mark.parametrize( ('number_range', 'type'), ( - ((2, 3), int), - ([-6, 8], int), - (8.5, float), - ([Decimal(2), 9], int), - ([Decimal('0.5'), 9], float), - ([date(2000, 1, 1), inf], date), - (('a', 'e'), str), + ((2, 3), int), + ([-6, 8], int), + (8.5, float), + ([Decimal(2), 9], int), + ([Decimal('0.5'), 9], float), + ([date(2000, 1, 1), inf], date), + (('a', 'e'), str), ) ) def test_guesses_types(self, number_range, type): @@ -208,12 +208,12 @@ 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), + (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( @@ -229,12 +229,12 @@ def test_raises_exception_for_badly_lower_changing( @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), + (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( From cbd49176d9833fd7ea04887bb0e28d2831e9027c Mon Sep 17 00:00:00 2001 From: easybase Date: Thu, 23 Jan 2020 11:20:56 +0800 Subject: [PATCH 10/11] fix: Range error detection when modify the lower or the upper property on an exist interval instance. before fixing: >>> interval = IntInterval([1, 2]) >>> interval IntInterval('[1, 2]') >>> interval.lower = 3 >>> interval IntInterval('[3, 2]') after fixing: >>> interval = IntInterval([1, 2]) >>> interval IntInterval('[1, 2]') >>> interval.lower = 3 >>> interval it will raise the RangeBoundsException: intervals.exc.RangeBoundsException: Min value 3 is bigger than max value 2. --- intervals/interval.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/intervals/interval.py b/intervals/interval.py index f6808e1..228d4d0 100644 --- a/intervals/interval.py +++ b/intervals/interval.py @@ -194,9 +194,9 @@ def range_init_and_setter_exception_detect(cls, lower, upper, lower_inc, upper_i upper ) if ( - lower == upper and - not lower_inc and - not 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 ' From dfe2f4bb5ce5692d0909923a3e1f4eb4ae0d2b92 Mon Sep 17 00:00:00 2001 From: easybase Date: Thu, 23 Jan 2020 16:34:19 +0800 Subject: [PATCH 11/11] fix: Range error detection when modify the lower or the upper property on an exist interval instance. before fixing: >>> interval = IntInterval([1, 2]) >>> interval IntInterval('[1, 2]') >>> interval.lower = 3 >>> interval IntInterval('[3, 2]') after fixing: >>> interval = IntInterval([1, 2]) >>> interval IntInterval('[1, 2]') >>> interval.lower = 3 >>> interval it will raise the RangeBoundsException: intervals.exc.RangeBoundsException: Min value 3 is bigger than max value 2. --- tests/interval/test_initialization.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/tests/interval/test_initialization.py b/tests/interval/test_initialization.py index 0ae9680..d75e0be 100644 --- a/tests/interval/test_initialization.py +++ b/tests/interval/test_initialization.py @@ -217,10 +217,10 @@ class TestIntervalChanging(object): ) ) def test_raises_exception_for_badly_lower_changing( - self, - constructor, - number_range, - bad_lower + self, + constructor, + number_range, + bad_lower ): with raises(RangeBoundsException): interval = constructor(number_range) @@ -238,10 +238,10 @@ def test_raises_exception_for_badly_lower_changing( ) ) def test_raises_exception_for_badly_upper_changing( - self, - constructor, - number_range, - bad_upper + self, + constructor, + number_range, + bad_upper ): with raises(RangeBoundsException): interval = constructor(number_range)