-
Notifications
You must be signed in to change notification settings - Fork 95
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add functionality for overriding dictionary merges. #61
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I haven't had a chance to actually test this change out yet, but a couple of overarching things from my read through of the patch:
- I'm trying to understand the role of the
initmerge
parameter, but probably need help getting it - We should probably provide some way for the user to escape the special meaning of
PARAMETER_DICT_KEY_OVERRIDE_PREFIX
Overall though, I think this is a great feature being done with the right implementation strategy
cur (dict): Current dictionary | ||
new (dict): Dictionary to be merged | ||
path (string): Merging path from recursion | ||
initmerge (bool): True if called as part of entity init |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is an example of a case in which a Parameters
object performs a merge as part of Entity
initialization? I don't see any merges that occur in Entity.__init__
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The merge is actually performed by Parameters.__init__
which happens to be called by Entity.__init__
. Lines 47-50 of Parameters.__init__
...
if mapping is not None:
# we initialise by merging, otherwise the list of references might
# not be updated
self.merge(mapping)
In actuality this happens, as far as I can tell, every time.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ahh, ok make total sense. The note could be a bit less confusing if edited to state "True if called as part of Parameters init" rather than "entity init".
path.new_subpath(key)) | ||
if key.startswith(ovrprfx) and not initmerge: | ||
ret[key.lstrip(ovrprfx)] = newvalue | ||
else: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that the case if key.startswith(overprfx) and initmerge
should be explicitly handled. I don't think we want to allow processed parameter keys to contain special characters without those characters being explicitly escaped.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree with this in principle but in practice it's a mite hairier... in reality processed parameter keys never actually reach the user because merge is called outside init in core. I've tested this by creating a node with no classes and "tilde-params". Furthermore if we strip them in the __init__
merge they do not exist as a signalling character during the "proper" merge, in which case it merges as normal (contrary to expectations).
I'm not averse to reformulating this conditional but I'd maybe like to see something that you think would work. I futzed with this a lot and there's some delicate interplay going between Parameters.__init__
and Core._nodeinfo
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm... I think I see what you're saying here. This certainly does present a practical implementation challenge. I think I need to get my hands dirty a bit with this feature to see how it all plays out.
@@ -188,6 +188,18 @@ def test_merge_dicts_overwrite(self): | |||
goal.update(mergee) | |||
self.assertDictEqual(p.as_dict(), dict(dict=goal)) | |||
|
|||
def test_merge_dicts_override(self): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hm yes unit tests.... A Very Good Idea
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was WAAAAY too tired when I wrote those. Replicated the functionality of other tests AND missed validating that we override properly on list extensions as well!
Much better and cleaner now.
RE 1. I'm trying to understand the role of the initmerge parameter, but probably need help getting it: The only time a RE 2. We should probably provide some way for the user to escape the special meaning of PARAMETER_DICT_KEY_OVERRIDE_PREFIX I'd like to open a separate non-blocking issue for this, the reason being that it'll be more consistent for users if the "special behavior character" is consistent between this and the applications negations (which are currently hardcoded with no escaping) and for the escaping system to also be consistent between those sections. |
Dictionary merges can now be overridden at any level by usage of a special character. The tilde is chosen as base default.
Makes total sense now, thanks! I might suggest revising this approach to go one of two ways though:
I think going at it one of these two ways will make the intent less confusing to read and would make the code itself more robust to changes
I certainly agree-- We have this problem elsewhere in the codebase right now, and we should solve it in a unified way, which probably requires its own dedicated effort. You're probably right in that it shouldn't block this merge, but since this merge does represent a breaking change with user data formats, and until that problem is solved the breakage will have no remediation, it's definitely a problem we'll need to address before another stable release |
I have pushed another commit that takes your preferred approach to the initmerge argument. I did not initially do it that way intentionally but I have been convinced that explicit is probably better. I did not rebase this one because I thought it would be good to keep the extra reversion point, JIC. |
Kickass job on implementing this feature! I'd say it's ready for a merge and some real-world testing |
It would be great if the same feature could also be implemented for the lists: overwriting a list instead of extending when the special |
@bbinet that is definitely how I /wanted/ to do it, but I hit some surprising complexity. If this represents a use case/need for you, please open and issue so that I have something to track it so I don't forget to work on this problem :-) |
Dictionary merges can now be overridden at any level by usage
of a special character. The tilde is chosen as base default.
This PR is a resolution to #60