diff --git a/confuse/cache.py b/confuse/cache.py index f61421a..ded336f 100644 --- a/confuse/cache.py +++ b/confuse/cache.py @@ -7,9 +7,8 @@ class CachedHandle(object): """Handle for a cached value computed by applying a template on the view. """ - # some sentinel objects _INVALID = object() - _MISSING = object() + """Sentinel object to denote that the cached value is out-of-date.""" def __init__(self, view: ConfigView, template=templates.REQUIRED) -> None: self.value = self._INVALID @@ -22,12 +21,8 @@ def get(self): Will re-compute the value using `view.get(template)` if it has been invalidated. - May raise a `NotFoundError` if the underlying view has been - invalidated. + May raise a `NotFoundError` if the underlying view is missing. """ - if self.value is self._MISSING: - # will raise a NotFoundError if no default value was provided - self.value = templates.as_template(self.template).get_default_value() if self.value is self._INVALID: self.value = self.view.get(self.template) return self.value @@ -37,11 +32,6 @@ def _invalidate(self): """ self.value = self._INVALID - def _set_view_missing(self): - """Invalidate the handle, will raise `NotFoundError` on `get()`. - """ - self.value = self._MISSING - class CachedViewMixin: def __init__(self, *args, **kwargs): @@ -62,9 +52,7 @@ def __getitem__(self, key) -> "CachedConfigView": def __setitem__(self, key, value): subview: CachedConfigView = self[key] # invalidate the existing handles up and down the view tree - for handle in subview.handles: - handle._invalidate() - subview._invalidate_descendants(value) + subview._invalidate_descendants() self._invalidate_ancestors() return super().__setitem__(key, value) @@ -82,24 +70,13 @@ def _invalidate_ancestors(self): break parent = parent.parent - def _invalidate_descendants(self, new_val): - """Invalidate the handles for (sub)keys that were updated and - set_view_missing for keys that are absent in new_val. + def _invalidate_descendants(self): + """Invalidate the handles for (sub)keys that were updated. """ + for handle in self.handles: + handle._invalidate() for subview in self.subviews.values(): - try: - subval = new_val[subview.key] - except (KeyError, IndexError, TypeError): - # the old key doesn't exist in the new value anymore- - # set view as missing for the handles. - for handle in subview.handles: - handle._set_view_missing() - subval = None - else: - # old key is present, possibly with a new value- invalidate. - for handle in subview.handles: - handle._invalidate() - subview._invalidate_descendants(subval) + subview._invalidate_descendants() def get_handle(self, template=templates.REQUIRED): """Retreive a `CachedHandle` for the current view and template. diff --git a/test/test_cache.py b/test/test_cache.py index e489f67..189044d 100644 --- a/test/test_cache.py +++ b/test/test_cache.py @@ -2,7 +2,6 @@ import confuse from confuse.cache import CachedConfigView, CachedHandle, CachedRootView -from confuse.exceptions import NotFoundError from confuse.templates import Sequence @@ -35,9 +34,9 @@ def test_missing(self): handle: CachedHandle = view.get_handle(Sequence(int)) self.config['x'] = {'p': [4, 5]} - # new dict doesn't have a 'y' key - with self.assertRaises(NotFoundError): - handle.get() + # new dict doesn't have a 'y' key, but according to the view-theory, + # it will get the value from the older view that has been shadowed. + self.assertEqual(handle.get(), [1, 2]) def test_missing2(self): view: CachedConfigView = self.config['x']['w'] @@ -45,9 +44,7 @@ def test_missing2(self): self.assertEqual(handle.get(), 'z') self.config['x'] = {'y': [4, 5]} - # new dict doesn't have a 'w' key - with self.assertRaises(NotFoundError): - handle.get() + self.assertEqual(handle.get(), 'z') def test_list_update(self): view: CachedConfigView = self.config['a'][1]