Repository: hgrecco/pint

Issue:
Handle infinity while parsing Quantity strings
As `str(some_quantity)` can produce strings like `"inf nm"`, would it be possible to go the other way such that `Quantity("inf nm") == Quantity(float("inf"), "nm")`, rather than erroring? `"nan"` is another possibility, although given that NaNs do not equal each other and a non-numeric quantity doesn't make a lot of sense, that's a lower priority.

Discussion:

Patch:
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 4b183a3..dfe7f24 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -1,10 +1,10 @@
 repos:
 -   repo: https://github.com/psf/black
-    rev: 21.9b0
+    rev: 21.11b1
     hooks:
     - id: black
 -   repo: https://github.com/pycqa/isort
-    rev: 5.9.3
+    rev: 5.10.1
     hooks:
     - id: isort
 -   repo: https://gitlab.com/pycqa/flake8
diff --git a/CHANGES b/CHANGES
index 7405124..44f56e2 100644
--- a/CHANGES
+++ b/CHANGES
@@ -7,7 +7,7 @@ Pint Changelog
 - Upgrade min version of uncertainties to 3.1.4
 - Fix setting options of the application registry (Issue #1403).
 - Fix Quantity & Unit `is_compatible_with` with registry active contexts (Issue #1424).
-
+- Allow Quantity to parse 'NaN' and 'inf(inity)', case insensitive
 
 0.18 (2021-10-26)
 -----------------
@@ -70,7 +70,7 @@ Pint Changelog
 - Fix tolist function with scalar ndarray.
   (Issue #1195, thanks jules-ch)
 - Corrected typos and dacstrings
-- Implements a first benchmark suite in airspeed velocity (asv). 
+- Implements a first benchmark suite in airspeed velocity (asv).
 - Power for pseudo-dimensionless units.
   (Issue #1185, thanks Kevin Fuhr)
 
diff --git a/docs/defining-quantities.rst b/docs/defining-quantities.rst
index 7ab7157..845c81c 100644
--- a/docs/defining-quantities.rst
+++ b/docs/defining-quantities.rst
@@ -144,6 +144,20 @@ brackets to get the expected result:
    >>> Q_('3 l / (100 km)')
    <Quantity(0.03, 'liter / kilometer')>
 
+Special strings for NaN (Not a Number) and inf(inity) are also handled in a case-insensitive fashion.
+Note that, as usual, NaN != NaN.
+
+.. doctest::
+
+   >>> Q_('inf m')
+   <Quantity(inf, 'meter')>
+   >>> Q_('-INFINITY m')
+   <Quantity(-inf, 'meter')>
+   >>> Q_('nan m')
+   <Quantity(nan, 'meter')>
+   >>> Q_('NaN m')
+   <Quantity(nan, 'meter')>
+
 .. note:: Since version 0.7, Pint **does not** use eval_ under the hood.
    This change removes the `serious security problems`_ that the system is
    exposed to when parsing information from untrusted sources.
diff --git a/pint/registry.py b/pint/registry.py
index 6bf4bb0..e3b5c77 100644
--- a/pint/registry.py
+++ b/pint/registry.py
@@ -1218,6 +1218,10 @@ class BaseRegistry(metaclass=RegistryMeta):
         if token_type == NAME:
             if token_text == "dimensionless":
                 return 1 * self.dimensionless
+            elif token_text.lower() in ("inf", "infinity"):
+                return float("inf")
+            elif token_text.lower() == "nan":
+                return float("nan")
             elif token_text in values:
                 return self.Quantity(values[token_text])
             else:


Test patch:
diff --git a/pint/testsuite/test_quantity.py b/pint/testsuite/test_quantity.py
index ddb242d..8f68262 100644
--- a/pint/testsuite/test_quantity.py
+++ b/pint/testsuite/test_quantity.py
@@ -617,6 +617,24 @@ class TestQuantity(QuantityTestCase):
         with self.ureg.context("sp"):
             assert a.is_compatible_with(b)
 
+    @pytest.mark.parametrize(["inf_str"], [("inf",), ("-infinity",), ("INFINITY",)])
+    @pytest.mark.parametrize(["has_unit"], [(True,), (False,)])
+    def test_infinity(self, inf_str, has_unit):
+        inf = float(inf_str)
+        ref = self.Q_(inf, "meter" if has_unit else None)
+        test = self.Q_(inf_str + (" meter" if has_unit else ""))
+        assert ref == test
+
+    @pytest.mark.parametrize(["nan_str"], [("nan",), ("NAN",)])
+    @pytest.mark.parametrize(["has_unit"], [(True,), (False,)])
+    def test_nan(self, nan_str, has_unit):
+        nan = float(nan_str)
+        ref = self.Q_(nan, " meter" if has_unit else None)
+        test = self.Q_(nan_str + (" meter" if has_unit else ""))
+        assert ref.units == test.units
+        assert math.isnan(test.magnitude)
+        assert ref != test
+
 
 class TestQuantityToCompact(QuantityTestCase):
     def assertQuantityAlmostIdentical(self, q1, q2):