diff options
author | Guido Imperiale <crusaderky@gmail.com> | 2019-12-09 15:58:36 +0000 |
---|---|---|
committer | Guido Imperiale <crusaderky@gmail.com> | 2019-12-09 15:58:36 +0000 |
commit | 157ebbfd3e9e6fc5def6b70a2c3f29f59cfdda77 (patch) | |
tree | 04c7f1e9a1cd3228ce209136f6222cf79d3bcdda | |
parent | 08c930dca43ba1625b1d6c6131d4f30765312676 (diff) | |
download | pint-157ebbfd3e9e6fc5def6b70a2c3f29f59cfdda77.tar.gz |
Fix bug in #909 where every time a context is reactivated it creates a brand new cache
-rw-r--r-- | CHANGES | 2 | ||||
-rw-r--r-- | pint/context.py | 25 | ||||
-rw-r--r-- | pint/registry.py | 2 |
3 files changed, 20 insertions, 9 deletions
@@ -15,7 +15,7 @@ Pint Changelog - TODO #913 - TODO #911 - Prevent 1500x slowdown when using .to() with a context - (Issue #909, Thanks Guido Imperiale) + (Issues #909 and #923, Thanks Guido Imperiale) - **BREAKING CHANGE**: Drop support for Python < 3.6, numpy < 1.14, and uncertainties < 3.0; if you still need them, please install pint 0.9. diff --git a/pint/context.py b/pint/context.py index c1782b5..fc27803 100644 --- a/pint/context.py +++ b/pint/context.py @@ -191,6 +191,18 @@ class Context: _key = self.__keytransform__(src, dst) return self.funcs[_key](registry, value, **self.defaults) + def hashable(self): + """Generate a unique hashable and comparable representation of self, which can + be used as a key in a dict. This class cannot define ``__hash__`` because it is + mutable, and the Python interpreter does cache the output of ``__hash__``. + """ + return ( + self.name, + tuple(self.aliases), + frozenset((k, id(v)) for k, v in self.funcs.items()), + frozenset(self.defaults.items()), + ) + class ContextChain(ChainMap): """A specialized ChainMap for contexts that simplifies finding rules @@ -209,7 +221,7 @@ class ContextChain(ChainMap): To facilitate the identification of the context with the matching rule, the *relation_to_context* dictionary of the context is used. """ - self._contexts.insert(0, contexts) + self._contexts = list(contexts) + self._contexts self.maps = [ctx.relation_to_context for ctx in reversed(contexts)] + self.maps self._graph = None @@ -244,10 +256,9 @@ class ContextChain(ChainMap): """ return self[(src, dst)].transform(src, dst, registry, value) - def context_ids(self): - """Hashable unique identifier of the current contents of the context chain. This - is not implemented as ``__hash__`` as doing so on a mutable object can provoke - unpredictable behaviour, as interpreter-level optimizations can cache the output - of ``__hash__``. + def hashable(self): + """Generate a unique hashable and comparable representation of self, which can + be used as a key in a dict. This class cannot define ``__hash__`` because it is + mutable, and the Python interpreter does cache the output of ``__hash__``. """ - return tuple(id(ctx) for ctx in self._contexts) + return tuple(ctx.hashable() for ctx in self._contexts) diff --git a/pint/registry.py b/pint/registry.py index 7e49ab5..3be1f5a 100644 --- a/pint/registry.py +++ b/pint/registry.py @@ -1137,7 +1137,7 @@ class ContextRegistry(BaseRegistry): return context def _build_cache(self): - key = self._active_ctx.context_ids() + key = self._active_ctx.hashable() try: self._cache = self._caches[key] except KeyError: |