Repository: hgrecco/pint

Issue:
unit redefinition in a context breaks transform in another context (again)
Reopen of #1062, which I thought I had fixed it in #1064.
I just realised that my PR only moved the problem further: before #1064 the POC was failing at the second iteration; now it fails on the third one.

```python
ureg = pint.UnitRegistry()
for i in range(3):
    print(f"run {i}")
    ctx = pint.Context.from_lines(["@context _", "cal = 4 J"])
    with ureg.context("sp", ctx):
        u = ureg.Unit("nm")
        q = ureg.Quantity(1, u)
        q.to('J')
```
Output:
```
run 0
run 1
run 2
KeyError: 'nanometer'
```

Discussion:

Patch:
diff --git a/CHANGES b/CHANGES
index d304263..f2229b0 100644
--- a/CHANGES
+++ b/CHANGES
@@ -22,7 +22,8 @@ Pint Changelog
 - Fixed issue where quantities with a very large magnitude would throw an IndexError 
   when using to_compact()
 - Fixed crash when a Unit with prefix is declared for the first time while a Context
-  containing unit redefinitions is active (Issue #1062, Thanks Guido Imperiale)
+  containing unit redefinitions is active
+  (Issues #1062 and #1097, Thanks Guido Imperiale)
 - New implementation of 'Lx' String Format Type Option
   The old implementation treated 'Lx' as 'S' as produced by 'uncertainties'
   package, but that is not fully compatible with SIunitx. The new code protects
@@ -37,6 +38,7 @@ Pint Changelog
 - Fix typo in docs for wraps example with optional arguments. (Issue #1088)
 - Add momentum as a dimension
 
+
 0.11 (2020-02-19)
 -----------------
 
@@ -77,6 +79,7 @@ Pint Changelog
   (Issue #881, Thanks Guido Imperiale)
 - Fixed __array__ signature to match numpy docs (Issue #974, Thanks Ryan May)
 
+
 0.10 (2020-01-05)
 -----------------
 
@@ -354,6 +357,7 @@ Pint Changelog
 - Allow changing shape for Quantities with numpy arrays.
   (Issue #344, thanks tecki)
 
+
 0.7.2 (2016-03-02)
 ------------------
 - Fixed backward incompatibility problem when parsing dimensionless units.
diff --git a/pint/measurement.py b/pint/measurement.py
index dd0f592..826253f 100644
--- a/pint/measurement.py
+++ b/pint/measurement.py
@@ -49,9 +49,7 @@ class Measurement(Quantity):
         if error is MISSING:
             mag = value
         elif error < 0:
-            raise ValueError(
-                "The magnitude of the error cannot be negative".format(value, error)
-            )
+            raise ValueError("The magnitude of the error cannot be negative")
         else:
             mag = ufloat(value, error)
 
diff --git a/pint/registry.py b/pint/registry.py
index 5e1e0fa..84544e1 100644
--- a/pint/registry.py
+++ b/pint/registry.py
@@ -1081,11 +1081,11 @@ class BaseRegistry(metaclass=RegistryMeta):
         """
 
         cache = self._cache.parse_unit
-        if as_delta:
-            try:
-                return cache[input_string]
-            except KeyError:
-                pass
+        # Issue #1097: it is possible, when a unit was defined while a different context
+        # was active, that the unit is in self._cache.parse_unit but not in self._units.
+        # If this is the case, force self._units to be repopulated.
+        if as_delta and input_string in cache and input_string in self._units:
+            return cache[input_string]
 
         if not input_string:
             return self.UnitsContainer()


Test patch:
diff --git a/pint/testsuite/test_issues.py b/pint/testsuite/test_issues.py
index 29c7905..6d1e5d1 100644
--- a/pint/testsuite/test_issues.py
+++ b/pint/testsuite/test_issues.py
@@ -693,10 +693,10 @@ class TestIssues(QuantityTestCase):
         assert isinstance(q1, ureg.Quantity)
         assert len(q0) == len(q1) == 0
 
-    def test_issue1062(self):
+    def test_issue1062_issue1097(self):
         # Must not be used by any other tests
         assert "nanometer" not in ureg._units
-        for i in range(2):
+        for i in range(5):
             ctx = Context.from_lines(["@context _", "cal = 4 J"])
             with ureg.context("sp", ctx):
                 q = ureg.Quantity(1, "nm")