-
Notifications
You must be signed in to change notification settings - Fork 9
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!: use sets for the state components #134
feat!: use sets for the state components #134
Conversation
very nice! |
Yeah, it seems wrong that |
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.
API changes look consistent with what we discussed -- good work! (I haven't done a line-by-line review -- maybe others can.)
One question I have: is it weird that users will be putting regular sets with {...}
syntax in, but get frozenset
s out? Should we just use regular old sets everywhere, even though they're "more mutable"?
I did wonder about this. I strongly believe that frozensets are the most appropriate data type - but it's super inconvenient to use them for the input since there's no literal syntax. It is a bit magic / inconsistent - but I think less so than if you were putting in an entirely different type. It's just "freezing" the content you put in, so I felt like that was ok. I do actually like that you can provide any iterable (of hashable objects) and you'll get the expected state object - so you can do I think it's also beneficial to increase the immutability of State, since we're expecting charmers to treat it as completely immutable. If it's possible to |
Yep, I agree with that reasoning -- duck/loose typing accepted as input, strict/best type used as output. |
The 'get' signatures have ended up more mixed than they were previously. Before:
Now:
@benhoyt @PietroPasotti would you still go with this? Having a bunch of "which set of arguments were passed and do they all agree with each other" code is a smell imo. I think it works ok for Container and Relation but less so for StoredState and Storage (and Secret is odd either way, because of the need to get by label). |
Is it an idea to use singledispatch? That would clean up the signatures imho, at the cost of more lines of code. |
TIL about @benhoyt and I talked this over and decided to start with the simpler key-only signatures (simplifying |
e1cf926
to
29bf3e5
Compare
* Remove _DCBase. * Adjust the consistency checker and expose the Resource class. * Finish the conversion (all tests pass). * Don't add __eq__ for now. * Update scenario/mocking.py * Allow getting components by passing in the old entity. * Revert back to the simpler get_ methods. * Fix merges. * Remove unused method (was used in the old binding, not generally useful). * Add a basic test for resources. * Add a basic test for resources. * Make networks a set as well.
The primary change is that instead of lists for the various
State
components (containers, relations, etc), frozensets are used.State
objects - ie. it's no longer possible to do something likestate.containers.append(Container(...))
, which people shouldn't have done previously, but would work.assert state_out.relations[0]....
To provide access to the components, and to avoid people needing to write many
rel = any(r for r in state_out.relations if r.id == id)
type statements, there are several new methods onState
:get_container
to get a container by name (this previously existed, and has been simplified to match the others, so it can no longer take aContainer
object)get_relation
to get a relation by IDget_stored_state
to get a stored state by name and owner pathget_storage
to get a storage by name and indexget_relation
to get a relation by IDget_network
to get a network by binding nameget_resource
andget_opened_port
are not added, because the charm cannot add or change resources, and ports don't have a unique identifier (it's more likely that tests want to check whether aPort
is contained in the set).There are two straight renames that change from singular to plural, since the state holds 0-n:
stored_state
becomesstored_states
(I can see that it's all "stored state", but there are multipleStoredState
objects, so the plural seems more correct)storage
becomesstorages
(charmcraft.yaml does use "storage", but I feel it's better to be consistent within Scenario than copy a perhaps-poor decision in the config)Several state components gain a custom
__hash__
method, so that they can be put into sets/frozensets. This also has the side-effect of removing the need to have the consistency checker check for duplicates, because a set/frozenset can't have a duplicate. It does mean that you can pass a set that has duplicates and not get a warning (Python just discards one item), but a linter should detect that issue, as with regular set use.The PR also introduces a
Resource
class to hold resources, so that they are consistent with all of the other components of the state.