Closed kalekundert closed 2 years ago
I ran into a problem implementing this: python doesn't let the instance dictionary shadow the descriptor if the descriptor implements __set__
or __del__
. So I'd need to get rid of those methods in order for this feature to be worth it. Can I do that?
__dict__
in get_meta()
, but that requires holding onto the cached value for all of time.get
won't be applied to values set by assignment, which means that get
basically won't work. The only way to deal with this is to use a different parameter class when the get
argument is specified. Some metaclass magic is necessary to hide this complexity from the user and any subclasses, but I did it, and it didn't turn out to be that bad.The metadata issue is the hangup. Even though it's a small feature, it's something that's squarely within appcli's purview, and there's just no way to get it right without __set__
.
I saved my work-in-progress to the feat-fast-cache
branch, but I'm going to abandon this feature for now.
The library would be much simpler conceptually if it were to just calculate a value the first time it was accessed, then overwrite itself with that value. AppCLI attributes just be elaborate default values: nothing more and nothing less.
The simplicity of this mental model really appeals to me, but I'd have to modify/eliminate some existing features:
cache_version
variable every time the configs change, and the attributes check that value every time they're accessed. In other words, the logic happens at access-time. To avoid this, I'd have to move this logic to load-time. That means I'd either keep track of every attribute that's been assigned to, or search the instance for overwritten attributes.frozen
/read_only
argument to force the use of a descriptor without a get/set callback. Thedynamic
argument discussed in #18 would also prevent overwriting.bind()
function. So if I want to get rid of this feature, I'll have to think about how I'd handle those use cases.Overall, this seems like it'd actually be a pretty small change. It wouldn't simplify the code at all (even though I still think of it as a conceptual simplification), because I'd have to keep all the current code to support these more complex cases. But I also wouldn't need to rewrite much existing code. Here's some pseudo-code:
update_in_progress == True
: Same as below, but cache instead of writing to instance dict.update_in_progress == False
: If have cached value, and the cache isn't stale, use it. Otherwise, recalculate. If get/set/frozen specified, write value to cache. If dynamic specified, don't write to cache. Otherwise, write value to instance dict and clear cache.