diff options
author | monopolis <epheon@gmail.com> | 2019-11-28 01:13:16 +0100 |
---|---|---|
committer | Alec Thomas <alec@swapoff.org> | 2019-11-28 11:13:16 +1100 |
commit | 858ceee119643bca099077e5a3ccbcb176292d1c (patch) | |
tree | 045f048921a97e1793a1472de10a5052534de4a9 | |
parent | f5e64dd7e26fb2de0ca4baec42c426c60cb061c2 (diff) | |
download | voluptuous-858ceee119643bca099077e5a3ccbcb176292d1c.tar.gz |
Handle incomparable values in Range (#414)
In Python3 some values that are comparable in Python2 are no longer
comparable. One instance of this is None, which in Python2 is always
less than any other object. In Python3, however, a TypeError is raised
if it is used in a comparison.
This commit handles said TypeError and issues a RangeInvalid exception
instead.
-rw-r--r-- | voluptuous/tests/tests.py | 13 | ||||
-rw-r--r-- | voluptuous/validators.py | 41 |
2 files changed, 37 insertions, 17 deletions
diff --git a/voluptuous/tests/tests.py b/voluptuous/tests/tests.py index 3ff71e4..acd6642 100644 --- a/voluptuous/tests/tests.py +++ b/voluptuous/tests/tests.py @@ -583,6 +583,19 @@ def test_range_exlcudes_nan(): assert_raises(MultipleInvalid, s, float('nan')) +def test_range_excludes_none(): + s = Schema(Range(min=0, max=10)) + assert_raises(MultipleInvalid, s, None) + + +def test_range_excludes_unordered_object(): + class MyObject(object): + pass + + s = Schema(Range(min=0, max=10)) + assert_raises(MultipleInvalid, s, MyObject()) + + def test_equal(): s = Schema(Equal(1)) s(1) diff --git a/voluptuous/validators.py b/voluptuous/validators.py index 328e2bf..0e0e1fc 100644 --- a/voluptuous/validators.py +++ b/voluptuous/validators.py @@ -585,23 +585,30 @@ class Range(object): self.msg = msg def __call__(self, v): - if self.min_included: - if self.min is not None and not v >= self.min: - raise RangeInvalid( - self.msg or 'value must be at least %s' % self.min) - else: - if self.min is not None and not v > self.min: - raise RangeInvalid( - self.msg or 'value must be higher than %s' % self.min) - if self.max_included: - if self.max is not None and not v <= self.max: - raise RangeInvalid( - self.msg or 'value must be at most %s' % self.max) - else: - if self.max is not None and not v < self.max: - raise RangeInvalid( - self.msg or 'value must be lower than %s' % self.max) - return v + try: + if self.min_included: + if self.min is not None and not v >= self.min: + raise RangeInvalid( + self.msg or 'value must be at least %s' % self.min) + else: + if self.min is not None and not v > self.min: + raise RangeInvalid( + self.msg or 'value must be higher than %s' % self.min) + if self.max_included: + if self.max is not None and not v <= self.max: + raise RangeInvalid( + self.msg or 'value must be at most %s' % self.max) + else: + if self.max is not None and not v < self.max: + raise RangeInvalid( + self.msg or 'value must be lower than %s' % self.max) + + return v + + # Objects that lack a partial ordering, e.g. None will raise TypeError + except TypeError: + raise RangeInvalid( + self.msg or 'value must have a partial ordering') def __repr__(self): return ('Range(min=%r, max=%r, min_included=%r,' |