Repository: wtforms/wtforms (python)

Issue:
validators.NumberRange doesn't handle NaN
Validating a `DecimalField` with a `NumberRange` validator throws a `decimal.InvalidOperation` exception when the value of the field is NaN. I would expect validation to fail instead
```
File "/usr/local/lib/python3.6/dist-packages/wtforms/form.py", line 310, in validate
  return super(Form, self).validate(extra)
File "/usr/local/lib/python3.6/dist-packages/wtforms/form.py", line 152, in validate
  if not field.validate(self, extra):
File "/usr/local/lib/python3.6/dist-packages/wtforms/fields/core.py", line 206, in validate
  stop_validation = self._run_validation_chain(form, chain)
File "/usr/local/lib/python3.6/dist-packages/wtforms/fields/core.py", line 226, in _run_validation_chain
  validator(form, self)
File "/usr/local/lib/python3.6/dist-packages/wtforms/validators.py", line 134, in __call__
  if data is None or (self.min is not None and data < self.min) or 
decimal.InvalidOperation: [<class 'decimal.InvalidOperation'>]
```


Pull request:
NumberRange can handle NaN values
This PR fixes #505.

Patch:
diff --git a/CHANGES.rst b/CHANGES.rst
index a8f47a4..3ee928e 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -67,6 +67,8 @@ Unreleased
 -   :class:`~validators.URL` validator now allows query parameters in the URL. (:pr:`523`, :pr:`524`).
 -   Updated French and Japanese translations. (:pr:`514`, :pr:`506`)
 -   form.errors is not cached and will update if an error is appended to a field after access. (:pr:`568`)
+-   :class:`~wtforms.validators.NumberRange` correctly handle *not a number*
+    values. (:pr:`505`, :pr:`548`)
 
 
 Version 2.2.1
diff --git a/README.rst b/README.rst
index 220ff78..a794d55 100644
--- a/README.rst
+++ b/README.rst
@@ -3,13 +3,8 @@ WTForms
 
 .. image:: https://travis-ci.org/wtforms/wtforms.svg?branch=master
     :target: https://travis-ci.org/wtforms/wtforms
-    :alt: Continuous Integration status
 .. image:: https://coveralls.io/repos/github/wtforms/wtforms/badge.svg?branch=master
     :target: https://coveralls.io/github/wtforms/wtforms?branch=master
-    :alt: Coverage status
-.. image:: https://readthedocs.org/projects/wtforms/badge/?version=stable
-    :target: https://wtforms.readthedocs.io/en/stable/?badge=stable
-    :alt: Documentation status
 .. image:: https://img.shields.io/badge/code%20style-black-000000.svg
     :target: https://github.com/psf/black
 
diff --git a/src/wtforms/validators.py b/src/wtforms/validators.py
index f274bd5..70cc1a0 100644
--- a/src/wtforms/validators.py
+++ b/src/wtforms/validators.py
@@ -1,5 +1,6 @@
 from __future__ import unicode_literals
 
+import math
 import re
 import uuid
 
@@ -191,6 +192,7 @@ class NumberRange(object):
         data = field.data
         if (
             data is None
+            or math.isnan(data)
             or (self.min is not None and data < self.min)
             or (self.max is not None and data > self.max)
         ):


Test patch:
diff --git a/tests/test_validators.py b/tests/test_validators.py
index e223c8d..a54a0c1 100644
--- a/tests/test_validators.py
+++ b/tests/test_validators.py
@@ -1,4 +1,5 @@
 # -*- coding: utf-8 -*-
+import decimal
 import pytest
 import re
 
@@ -589,6 +590,14 @@ def test_number_range_raises(min_v, max_v, test_v, dummy_form, dummy_field):
         validator(dummy_form, dummy_field)
 
 
+@pytest.mark.parametrize("nan", [float("NaN"), decimal.Decimal("NaN")])
+def test_number_range_nan(nan, dummy_form, dummy_field):
+    validator = NumberRange(0, 10)
+    dummy_field.data = nan
+    with pytest.raises(ValidationError):
+        validator(dummy_form, dummy_field)
+
+
 @pytest.mark.parametrize("test_function", [str, text_type])
 def test_lazy_proxy_raises(test_function, really_lazy_proxy):
     """