Replies: 2 comments 3 replies
-
Modifying the "parent" env as you've described seems reasonable to me, for values not in the override. For delete.. more complicated, but probably same answer. Separating the behavior from whether a builder should delete from the passed env. If you did a delete on a dict and then it wasn't really deleted, that'd be surprising.. (not the good kind). That said, I did some experiments a while back with locking an Environment() with the ideal of pre-subst'ing all values which could be. Didn't get around to completing that experiment, but I can see real value in locking an env, and/or being able to lock some values in the env from modification, and indeed there's already a mechanism for such for |
Beta Was this translation helpful? Give feedback.
-
someone in that context = not a core SCons developer for internal code.. |
Beta Was this translation helpful? Give feedback.
-
An
OverrideEnvironment
maps a dict on top of a dict: underneath is the_dict
attribute of the calling Environment, and on top is theoverrides
attribute of the OE. Attribute fetches pull fromoverrides
first, then from the backing dict. Assignment is tooverrides
only, you don't update the base Environment when assigning (__setattr__
).The
OverrideEnvironment
class has a__delitem__
method, but what it should actually do is not obvious. Let's illustrate with a contrived example:Consider override env
over
where:Then:
over['a']
returns 1: it's only inoverrides
.over['b']
returns 2: fromoverrides
, which wins overbase
.over['c']
returns 4: fetched frombase
because it wasn't found inoverrides
.Currently,
del over['a']
deletes'a'
fromoverrides
.del over['b']
deletes'b'
fromoverrides
andbase
.del over['c']
deletes'c'
frombase
.Case 1 is "obvious". Cases 2 and 3 are less so. Should deleting an item from our dictionary "view" ever modify the backing dictionary? That seems contrary to the spirit of a "temporary override" that is used to keep from having to change your active env. Case 2 is especially interesting - it is apparently designed so that if you delete from your view, then the key you deleted is no longer in your view, but it does that by modifying the backing dict.
For comparison purposes, Python introduced a
ChainMap
class (in 3.3 I believe) which provides a rough approximation of this approach - the definition there is you can have a chained list of dicts, with attribute access taking place on a left-to-right lookup basis, but only the first dict in the chain is allowed to be modified. The same example would work that way there:del over['a']
deletes'a'
fromoverrides
.del over['b']
deletes'b'
fromoverrides
.del over['c']
raises exception, not allowed to delete frombase
.But it's not obvious this is what we want either: now
over['b']
returns 3 (the value frombase
) instead of 2 (the now-deleted value fromoverrides
), so we didn't actually delete it from our view.So that's an interpretation question: does 'del' mean delete from the view, or does it mean delete the overriden version but possibly let a value from the base show though?
This sounds nitpicky: code which creates an override isn't terribly likely to do any deleting, it's normally interested in just adding one or more values to create the overrride. But an
OverrideEnvironment
, created by the factory function, is just returned and then passed around like any other env, somebody being passed one of those doesn't know it's anything special, and it would likely be too expensive to putisinstance
checks all over the place for something which isn't the "normal case" - most times an env is a real env. I think there's a general feeling that "callbacks" and other build-time things should not modify an env they're passed, but I don't believe that's ever explicitly stated nor is there any reasonable way to enforce that ("code reviews" withing the SCons codebase itself, I guess, but doesn't help for external code).It's possible (the implementation is easy enough) to record keys explicitly requested for deletion, delete them only from the override, use the saved delete info to refuse to serve them from the underlying environment, which would solve the "if was deleted, don't let it look like it still exists" question in a different way than we do now. Or could take an approach more like
ChainMap
which doesn't delete from the underlying but still serves up from there on request. Or one could make__delitem__
entirely disallowed.===
There's another instance of "leakage" through to the underlying env that's much harder to prevent - if the value for a given key is a mutable object, changing it through the override view changes the same object. Maybe that's a separate topic (and it's a general Python topic, not unique to SCons - calls for things like immutable dicts have been considered too niche to add to core, and the PEPs have been rejected, so that's going nowhere).
Just for grins, here's an extension to
EnvironmentTests
that shows this leakage:leading to:
Beta Was this translation helpful? Give feedback.
All reactions