summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGuido Imperiale <crusaderky@gmail.com>2019-12-09 15:58:36 +0000
committerGuido Imperiale <crusaderky@gmail.com>2019-12-09 15:58:36 +0000
commit157ebbfd3e9e6fc5def6b70a2c3f29f59cfdda77 (patch)
tree04c7f1e9a1cd3228ce209136f6222cf79d3bcdda
parent08c930dca43ba1625b1d6c6131d4f30765312676 (diff)
downloadpint-157ebbfd3e9e6fc5def6b70a2c3f29f59cfdda77.tar.gz
Fix bug in #909 where every time a context is reactivated it creates a brand new cache
-rw-r--r--CHANGES2
-rw-r--r--pint/context.py25
-rw-r--r--pint/registry.py2
3 files changed, 20 insertions, 9 deletions
diff --git a/CHANGES b/CHANGES
index 16cc515..803e0c6 100644
--- a/CHANGES
+++ b/CHANGES
@@ -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: