web2py/web2py — pull request #254 by pochmann (2013-10-12 20:20:07+00:00)
Title: Improvements for number range validators

First commit is fixes, especially that 0 wasn't accepted, for example `IS_INT_IN_RANGE(-5,5)(0)` misbehaved.

Second commit is for consistency. `IS_INT_IN_RANGE(None,None,'')('foo')` misbehaved because unlike the other eleven cases, `error_message` wasn't compared against None. And the word `decimal` was inconsistent with the other seven decimal/float cases, especially the corresponding None/None case of the float range validator.

Third commit is a rewrite of the three number range validator constructors. I found especially the old integer one very complicated, confusing and repetitive. Unless my thinking and tests failed, this should be a pure code rewrite, no change in behavior. My first two commits prepared for this.

Doctests and unittests look good, and I additionally ran a lot of tests with which I found the errors/inconsistencies fixed by my first two commits. My additional tests compared attributes and validation results of the validators before and after my third commit. They find no differences. Here's the code, in case you'd like to see:

```
mins = [-10, None]
maxs = [10, None, 9.5, 10.5, -10**98, 10**98, 2**31, 2**31-1, 2**31+1, 2**60, 10**10]
error_messages = ['foo', None, '']
values = [-11, -10, -9, -1, 0, 1, 9, 10, 11, '+2', 'bar', None, '', '0xF', '3.14', 3.14, '3.0', 3.0, 10**99, -10**99]
vali_pairs = ((new2_IS_INT_IN_RANGE, curr_IS_INT_IN_RANGE),
(new2_IS_FLOAT_IN_RANGE, curr_IS_FLOAT_IN_RANGE),
(new2_IS_DECIMAL_IN_RANGE, curr_IS_DECIMAL_IN_RANGE))

def compare_attributes(a, b):
for attr in dir(a):
if attr not in dir(b):
print("differ:\n {}\n has '{}'\n {}\n doesn't".format(
a, attr, b))
else:
if not attr.startswith('__') and getattr(a, attr) != getattr(b, attr):
print("differ:\n {}\n '{}' is '{}'\n {}\n '{}' is '{}'".format(
a, attr, getattr(a, attr), b, attr, getattr(b, attr)))
for attr in dir(b):
if attr not in dir(a):
print("differ:\n {}\n has '{}'\n {}\n doesn't".format(
b, attr, a))

print('start comparing')
for vali_new, vali_cur in vali_pairs:
print(" comparing {}".format(vali_new))
for min in mins:
for max in maxs:
for error_message in error_messages:
v_new = vali_new(min, max, error_message)
v_cur = vali_cur(min, max, error_message)
compare_attributes(v_new, v_cur)
for value in values:
if v_new(value) != v_cur(value):
print(min, max, error_message, value, v_new(value), v_cur(value))
print('done comparing')
```

I'm fairly new to Python/web2py/git/GitHub, but I think my improvements are good and that I did things correctly. If not, please let me know.