Skip to content

Commit

Permalink
Parse inf and nan in Quantity
Browse files Browse the repository at this point in the history
Resolves #1432

Case-insensitive; also accepts "infinity".
  • Loading branch information
clbarnes authored and jules-ch committed Dec 9, 2021
1 parent f287768 commit 80bdd5e
Show file tree
Hide file tree
Showing 4 changed files with 38 additions and 2 deletions.
4 changes: 2 additions & 2 deletions CHANGES
Original file line number Diff line number Diff line change
Expand Up @@ -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)
-----------------
Expand Down Expand Up @@ -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)

Expand Down
14 changes: 14 additions & 0 deletions docs/defining-quantities.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
4 changes: 4 additions & 0 deletions pint/registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -1218,6 +1218,10 @@ def _eval_token(self, token, case_sensitive=None, use_decimal=False, **values):
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:
Expand Down
18 changes: 18 additions & 0 deletions pint/testsuite/test_quantity.py
Original file line number Diff line number Diff line change
Expand Up @@ -617,6 +617,24 @@ def test_is_compatible_with_with_context(self):
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):
Expand Down

0 comments on commit 80bdd5e

Please sign in to comment.