-
Notifications
You must be signed in to change notification settings - Fork 123
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
feat: efficient implementation of RelationDataContent.update #1586
feat: efficient implementation of RelationDataContent.update #1586
Conversation
f50f18e
to
0d0df7d
Compare
I've broken the tests. I'm going to iterate on the efficient approach to unify the single/multiple update code paths as much as possible, and then I'll update the test side of things (may need some little modifications to harness/scenario). |
487fec5
to
f1f1776
Compare
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 this is definitely the right approach. It's looking really great!
On testing:
- You should definitely add a testing/tests test, probably in test_relations. Basically the same kind of thing as you have for harness/test_testing, but for Scenario. I'd also include one that checks that removing a key works (which I think will fail currently!).
- I don't think there's a test for the "I gave setitem an empty dict" case raising an error. It would be good to have one if it's not too complicated.
- I don't think there's any relation-set checking in test_main at the moment, but it feels like this is maybe a good opportunity to add some, which could include this. Basically just verifying that relation-get and relation-set are called properly, including in this new flow. At the moment there's quite an assumption that it works ok since the tests (like much of test_model!) rely on Harness.
676f25a
to
ed71134
Compare
…l sites TODO: update tests and call sites so that update_relation_data can have a sane signature
_ModelBackend.relation_set in ops now handles a dictionary of key-value pairs instead of a single key and value
This is an efficient implementation of update that replaces the original, inefficient implementation inherited from MutableMapping.
ed71134
to
8854be8
Compare
The docs fail because it looks like your code is a "block quote". You can fix it like: diff --git a/ops/model.py b/ops/model.py
index 61ed63d..2e564af 100644
--- a/ops/model.py
+++ b/ops/model.py
@@ -1947,11 +1947,12 @@ class RelationDataContent(LazyMapping, MutableMapping[str, str]):
) -> None:
"""Efficiently write multiple keys and values to the databag.
- Has the same ultimate result as this, but uses a single relation-set call:
- for k, v in dict(data).items():
- self[k] = v
- for k, v in kwargs.items():
- self[k] = v
+ Has the same ultimate result as this, but uses a single relation-set call::
+
+ for k, v in dict(data).items():
+ self[k] = v
+ for k, v in kwargs.items():
+ self[k] = v
"""
data = dict(data)
data.update(kwargs) Although I think maybe it's only the extra The PR title needs updating, as you did with the description. |
We probably need a comment on #817 that explains why |
@@ -513,7 +531,6 @@ def test_relation_data_del_missing_key(self, harness: ops.testing.Harness[ops.Ch | |||
('relation_ids', 'db1'), | |||
('relation_list', relation_id), | |||
('relation_get', relation_id, 'myapp/0', False), | |||
('update_relation_data', relation_id, harness.model.unit, 'port', ''), |
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.
Deleting an already missing key no longer hits the backend
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.
Looks really great - thanks for making those changes!
It's a shame that we can't really do the originally requested feature, but I think this is a nice performance improvement, and it generally makes the code nicer since it follows Juju more closely.
This PR makes it efficient to add/update/delete multiple keys and values in your relation data, by overriding the default implementation of
RelationDataContent.update
(provided byMutableMapping
) with an efficient implementation that calls therelation-set
hook tool only once. The changes to internals that back the newupdate
implementation are exercised by existing tests interacting withRelationDataContent.update
andRelationDataContent.__setitem__
.Both Harness and Scenario's model backend implementations require updates to accommodate this. The Harness backend is exercised in the existing Ops tests. The Scenario updates are exercised in new tests added to
testing/tests/test_e2e/test_relations.py
.Original description, now outdated, but retained to explain the original motivation for this work:
This PR resolves #817 by adding
RelationData.__setitem__(self, key, value)
. This allows users to writemy_relation[app_or_unit] = {'key-value': 'pairs'}
, instead of having to fetch theRelationDataContent
object withmy_relation[app_or_unit]
and then update its keys and values directly.The implementation of
RelationData.__setitem__
gets the currentRelationDataContent
for thekey
, callsRelationDataContent.clear()
(provided byRelationDataContent
's inheritance fromMutableMapping
-- the inherited implementation will callRelationDataContent
's custom__delitem__
), and then calls the existingRelationDataContent.update(value)
method. This ensures that validation and updating the backend occurs exactly as it would have if the user interacted withRelationDataContent
directly.RelationData.__setitem__
will raise aKeyError
if thekey
is not actually a knownApplication
orUnit
.