Browse Source
This commit is a fairly large chunk of code that fixes a previously annoying and nasty bug causing cached_properties to not be cleared. Alongside this bug fix I took the opportunity to refactor the entire methdology behind cached properties, and bind them more strictly to the behavior of models. Prior to this commit, cached_properties where not be properly reset upon a model's `update` method being called due to some invalid code. Along with this issue, the actual behavior of cached properties landed in a weird in-between/gray area where they had to support both non-model and model use cases. The new version of cached_property is strictly for use with models, and another version `simple_cached_property` was added to support other use cases. The new cached_property simply builds an actual `property` within the metaclass. This is fairly efficient, and also reduces the surface area of behavior. When writing this I messed around with a few ideas, including allowing the user of `cached_property` to define a linkage between the property and fields that should invalidate its cached value, but this was both messy and introduced massive cognitive load on understand when a cached_property should be cleared. Although this version is slighty less efficient, I'm very much in favor of it vs the alternatives I tried.pull/50/head
12 changed files with 132 additions and 46 deletions
@ -0,0 +1,31 @@ |
|||||
|
import pytest |
||||
|
|
||||
|
from disco.types.base import Model, Field, cached_property |
||||
|
|
||||
|
|
||||
|
@pytest.fixture |
||||
|
def model(): |
||||
|
class TestModel(Model): |
||||
|
a = Field(int) |
||||
|
b = Field(int) |
||||
|
|
||||
|
@cached_property |
||||
|
def value(self): |
||||
|
return self.a + self.b |
||||
|
|
||||
|
return TestModel |
||||
|
|
||||
|
|
||||
|
def test_cached_property(model): |
||||
|
inst = model(a=1, b=3) |
||||
|
assert inst.value == 4 |
||||
|
|
||||
|
inst.a = 2 |
||||
|
assert inst.value == 4 |
||||
|
|
||||
|
|
||||
|
def test_cached_property_clear_on_update(model): |
||||
|
inst = model(a=1, b=3) |
||||
|
assert inst.value == 4 |
||||
|
inst.update(model(a=2, b=3)) |
||||
|
assert inst.value == 5 |
@ -0,0 +1,21 @@ |
|||||
|
from disco.util.functional import simple_cached_property |
||||
|
|
||||
|
|
||||
|
def test_simple_cached_property(): |
||||
|
class Test(object): |
||||
|
def __init__(self, a, b): |
||||
|
self.a = a |
||||
|
self.b = b |
||||
|
|
||||
|
@simple_cached_property |
||||
|
def value(self): |
||||
|
return self.a + self.b |
||||
|
|
||||
|
inst = Test(1, 1) |
||||
|
assert inst.value == 2 |
||||
|
|
||||
|
inst.a = 4 |
||||
|
assert inst.value == 2 |
||||
|
|
||||
|
del inst.value |
||||
|
assert inst.value == 5 |
Loading…
Reference in new issue