You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
As of 0.14, the "use either attribute or dict syntax" behavior for Context/Config/DataProxy functions reasonably well, except for when setting brand new config keys that don't already exist, in which case the attribute approach doesn't work - it simply sets a real attribute on whatever DataProxy is being touched.
This is very foot-gunny as it leads to difficult to understand/troubleshoot behavior - no error, and attribute access sometimes works after due to happenstance, but any e.g. cloning of the config, or dict access, or etc, does not preserve the attribute; tests like "if key in config" fail; etc.
What should happen is that new attribute accesses do set config values...but only from "outside" the class, and not in, say, __init__, otherwise there's a chicken/egg problem re: how to set initial, real attributes.
Strongly related is an issue where the "real attributes win over config values w/ same name, during attribute access" behavior - changed for 0.14 - is inconsistent because it only looks at self/type, and not supertypes, so it still doesn't quite work when one is dealing with Context or Config (versus a nested config values, which becomes a 'raw' DataProxy).
Solutions
'Lock'/'unlock' attributes-become-config behavior, e.g. in a decorator around __init__ or other methods
Should work pretty solidly
But requires implementers of subclasses to remember to use the decorator anyplace they create new attributes
And is moderate bookkeeping, i.e. keep an attribute around as state for whether the obj is in "let me touch attrs or not" mode
which then rolls into the supertypes issue above, because if that's not working, Context and Config both need their own initializations of the bookkeeping attribute
besides that, it's just more state that can get set incorrectly, or cause threading issues, etc
Main upside: when decorator is in place, decorated code can simply forget about the whole deal and use attributes normally
Just remember to use object.__setattr__ anytime one makes new attributes, which skips our "clever" local implementation entirely.
Bit more footgunny for devs insofar as it's now a lot easier to forget (any attribute creation vs just set & forget once per method, with the above decorator approach)
Also just more verbose
Might have some quirks on eg Python 3 (tho I can't find the NOTE: I thought I left about this in the deep past...)
But it's less bookkeeping
Neither of those is a clear winner but I'm leaning towards the latter (less code and state is better) so I may try it first to see just how verbose it is and whether it even works as expected.
The text was updated successfully, but these errors were encountered:
object.__setattr__ appears to do the job, including under Python 3. Yea, it makes Config.__init__ a good amount more verbose (we initialize a few dozen attributes there) but I still feel better about doing it this way vs introducing more custom state crap.
My real world code that was working around this via dict-style setting, also appears to work fine with this change in place. Yay.
Background
As of 0.14, the "use either attribute or dict syntax" behavior for Context/Config/DataProxy functions reasonably well, except for when setting brand new config keys that don't already exist, in which case the attribute approach doesn't work - it simply sets a real attribute on whatever DataProxy is being touched.
This is very foot-gunny as it leads to difficult to understand/troubleshoot behavior - no error, and attribute access sometimes works after due to happenstance, but any e.g. cloning of the config, or dict access, or etc, does not preserve the attribute; tests like "if key in config" fail; etc.
What should happen is that new attribute accesses do set config values...but only from "outside" the class, and not in, say,
__init__
, otherwise there's a chicken/egg problem re: how to set initial, real attributes.Strongly related is an issue where the "real attributes win over config values w/ same name, during attribute access" behavior - changed for 0.14 - is inconsistent because it only looks at self/type, and not supertypes, so it still doesn't quite work when one is dealing with
Context
orConfig
(versus a nested config values, which becomes a 'raw' DataProxy).Solutions
__init__
or other methodsobject.__setattr__
anytime one makes new attributes, which skips our "clever" local implementation entirely.Neither of those is a clear winner but I'm leaning towards the latter (less code and state is better) so I may try it first to see just how verbose it is and whether it even works as expected.
The text was updated successfully, but these errors were encountered: