Implement a CachedCall to handle boilerplate of caching results#9353
Implement a CachedCall to handle boilerplate of caching results#9353richvdh wants to merge 2 commits into
Conversation
This feels like a relatively common pattern which is hard to get right. I've used `oidc.jwks` as an example for how it could be used.
|
I'm interested in thoughts on this. I don't think the tests are passing; in any case, if it's a good idea, I want to add unit tests. But if the answer is "why don't you just ....", then I won't pursue it further. |
| self._deferred = None # type: Optional[Deferred] | ||
| self._result = None # type: Union[None, Failure, TV] | ||
|
|
||
| async def get(self) -> TV: |
There was a problem hiding this comment.
Maybe slighter nicer ergonomics if we used __call__ instead?
This would let you do something like:
async def handle_request() -> X:
# We can call this multiple times, but it will result in a single call to
# _load_prop().
return await _cached_val()This feels a bit nicer since you've wrapped a function and then it returns a function-like thing and might let you use it as a decorator?
There was a problem hiding this comment.
hrm, maybe. I always feel like relying on __call__ is a bit magical, and tend to prefer that the interactions are made explicit, which is why I did it this way. I could be persuaded though.
There was a problem hiding this comment.
My thought is that it makes it more like functools.cached_property, but perhaps that isn't the goal. 😄
| # I *think* this is the easiest way to correctly raise a Failure without having | ||
| # to gut-wrench into the implementation of Deferred. | ||
| d = Deferred() | ||
| d.callback(self._result) | ||
| return await d |
There was a problem hiding this comment.
I'm not sure this will work properly for errors, do we need to call d.errback if it is an instance of Failure? (I don't think Deferred does anything special if you callback a Failure.)
There was a problem hiding this comment.
It does work, because errback(x) and callback(x) are both just thin wrappers around _startRunCallbacks(x). You could argue that this isn't using Deferred's API as it's intended, which might be fair.
|
This is now superceded by #9362. |
This feels like a relatively common pattern which is hard to get right.
I've used
oidc.jwksas an example for how it could be used.