Fix #174: Improve popitem() exception context handling.
diff --git a/cachetools/lfu.py b/cachetools/lfu.py
index 341df01..adb45ee 100644
--- a/cachetools/lfu.py
+++ b/cachetools/lfu.py
@@ -28,6 +28,7 @@
try:
(key, _), = self.__counter.most_common(1)
except ValueError:
- raise KeyError('%s is empty' % self.__class__.__name__)
+ msg = '%s is empty' % self.__class__.__name__
+ raise KeyError(msg) from None
else:
return (key, self.pop(key))
diff --git a/cachetools/lru.py b/cachetools/lru.py
index b72b995..7634f9c 100644
--- a/cachetools/lru.py
+++ b/cachetools/lru.py
@@ -28,7 +28,8 @@
try:
key = next(iter(self.__order))
except StopIteration:
- raise KeyError('%s is empty' % self.__class__.__name__)
+ msg = '%s is empty' % self.__class__.__name__
+ raise KeyError(msg) from None
else:
return (key, self.pop(key))
diff --git a/cachetools/rr.py b/cachetools/rr.py
index 88ac07c..30f3822 100644
--- a/cachetools/rr.py
+++ b/cachetools/rr.py
@@ -29,6 +29,7 @@
try:
key = self.__choice(list(self))
except IndexError:
- raise KeyError('%s is empty' % self.__class__.__name__)
+ msg = '%s is empty' % self.__class__.__name__
+ raise KeyError(msg) from None
else:
return (key, self.pop(key))
diff --git a/cachetools/ttl.py b/cachetools/ttl.py
index 3bac52e..7822e8b 100644
--- a/cachetools/ttl.py
+++ b/cachetools/ttl.py
@@ -198,7 +198,8 @@
try:
key = next(iter(self.__links))
except StopIteration:
- raise KeyError('%s is empty' % self.__class__.__name__)
+ msg = '%s is empty' % self.__class__.__name__
+ raise KeyError(msg) from None
else:
return (key, self.pop(key))
diff --git a/tests/__init__.py b/tests/__init__.py
index 0be3f32..82f85ef 100644
--- a/tests/__init__.py
+++ b/tests/__init__.py
@@ -1,3 +1,7 @@
+import sys
+import unittest
+
+
class CacheTestMixin(object):
Cache = None
@@ -104,6 +108,18 @@
with self.assertRaises(KeyError):
cache.popitem()
+ @unittest.skipUnless(sys.version_info >= (3, 7), 'requires Python 3.7')
+ def test_popitem_exception_context(self):
+ # since Python 3.7, MutableMapping.popitem() suppresses
+ # exception context as implementation detail
+ exception = None
+ try:
+ self.Cache(maxsize=2).popitem()
+ except Exception as e:
+ exception = e
+ self.assertIsNone(exception.__cause__)
+ self.assertTrue(exception.__suppress_context__)
+
def _test_missing(self, cache):
self.assertEqual(0, cache.currsize)
self.assertEqual(2, cache.maxsize)