Skip to content
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: support 'ctx.on.event_name()' for specifying events #126

Merged
merged 25 commits into from
Jun 6, 2024

Conversation

tonyandrewmeyer
Copy link
Collaborator

@tonyandrewmeyer tonyandrewmeyer commented Apr 24, 2024

This PR adds the ability to specify the event to run using ctx.on, for example:

# Simple events:
ctx.run(ctx.on.install(), state)

# Secret events:
ctx.run(ctx.on.secret_changed(secret=secret), state)
ctx.run(ctx.on.secret_expired(secret, revision=revision), state)

# Storage events:
ctx.run(ctx.on.storage_attached(storage=storage), state)

# Action events:
ctx.run_action(action, state)

# Container events:
ctx.run(ctx.on.pebble_ready(container=container), state)

# Relation events:
ctx.run(ctx.on.relation_created(relation=relation), state)
ctx.run(ctx.on.relation_changed(relation), state)
ctx.run(ctx.on.relation_changed(relation, remote_unit=unit_ordinal), state)
ctx.run(ctx.on.relation_departed(relation, remote_unit=unit_ordinal, departing_unit=unit_ordinal), state)

This also removes the ability to run custom events explicitly (they are still run implicitly when a Juju event triggers them). As discussed previously, if there's demand for this in the future then we'll consider adding it back, and decide on an API at that time.

A few fixes slipped in:

  • tox -e lint-tests was linting both tests and the main code, which I assume it was not meant to do
  • event.unit in a -relation-broken and a -relation-created event should always be None
  • I don't think that the existing code handles secret revisions in secret-expired and secret-removed (at least I couldn't figure out how to get it to work), so that's also done here

@PietroPasotti
Copy link
Collaborator

PietroPasotti commented Apr 24, 2024

one note: not sure we can hide Event as that is necessary for testing custom events.

edit: scratch that, I see now you were proactively removing support for that use case.

@tonyandrewmeyer
Copy link
Collaborator Author

@PietroPasotti and @benhoyt are you both ok with this proposal, e.g. the usage as outlined in the PR description? If so, then I'll go ahead and polish this PR up so that it's in a properly reviewable, but it would nice to have a tentative yes for the approach first.

@PietroPasotti
Copy link
Collaborator

PietroPasotti commented May 31, 2024

In principle I'm ok with the approach, although I'm not sure I like it more than the original.
Two doubts I have left, ux-wise, are:

1- how often will the user try to do:

ctx.run(ctx.on.baz_relation_departed, state)

only to find out that the ordinal arguments are required?
Do we add two separate event types to make at least the type checkers aware that you can't just pass whatever ctx.on.baz_relation_departed is to ctx.run() without calling it first?

It would be easier if all events were callable (and HAD TO be called when passing them to .run()).

2- Why are some on.x callable and some not?
What happens if you try to ctx.run(ctx.on.install(), state) instead of ctx.run(ctx.on.install, state)?
Again it would be easier if all events were callable (and HAD TO be called when passing them to .run()).

Counterproposal

# Simple events: no args
ctx.run(ctx.on.install(), state)

# Secret events:
ctx.run(ctx.on.secret_changed(secret=secret), state)
ctx.run(ctx.on.secret_expired(secret=secret, revision=revision), state)

# Storage events:
# storage = Storage("foo", ...)
# state = State(storages={storage})
ctx.run(ctx.on.storage_attached(storage=storage, state)

# Action events:
ctx.run_action(ctx.on.action(action=action), state)

# Container events:
ctx.run(ctx.on.pebble_ready(bar_container), state)

# Relation events:
ctx.run(ctx.on.relation_created(relation=baz), state)
ctx.run(ctx.on.relation_changed(relation=baz), state)
ctx.run(ctx.on.relation_changed(relation=baz, unit=unit_ordinal), state)
ctx.run(ctx.on.relation_departed(relation=baz, unit=unit_ordinal, departing_unit=unit_ordinal), state)

it's also way better for autocompletion, since ctx.on.foo_relation_changed would be trouble to dynamically populate.

@benhoyt
Copy link
Collaborator

benhoyt commented Jun 3, 2024

Yeah, I kind of like the consistency and type-simplicity of @PietroPasotti's "counterproposal". @tonyandrewmeyer let's discuss today in our 1:1 and see if we can come to agreement here.

@tonyandrewmeyer
Copy link
Collaborator Author

Decision is to go with Pietro’s counterproposal. Keep ctx.on because it’s a nice signal that it’s “an event type thing” and nice namespace/autocomplete. Also, Zen of Python says “If the implementation is easy to explain, it may be a good idea.”

The failing test are (a) ones that need to be rewritten for the new system, (b) ones to do with custom events.
These are not as valuable without support for emitting custom events directly, but it seems worthwhile to leave them in so that if we add custom event emitting back in the future they're here to build off.
@tonyandrewmeyer tonyandrewmeyer changed the title feat: support 'ctx.on.event_name' for specifying events feat: support 'ctx.on.event_name()' for specifying events Jun 5, 2024
@tonyandrewmeyer tonyandrewmeyer marked this pull request as ready for review June 5, 2024 07:53
Copy link
Collaborator

@PietroPasotti PietroPasotti left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks great! looking forward to trying it out :)

@@ -245,7 +247,12 @@ def _get_event_env(self, state: "State", event: "Event", charm_root: Path):
remote_unit = f"{remote_app_name}/{remote_unit_id}"
env["JUJU_REMOTE_UNIT"] = remote_unit
if event.name.endswith("_relation_departed"):
env["JUJU_DEPARTING_UNIT"] = remote_unit
if event.relation_departed_unit_id:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

huh, good catch. this was wrong

scenario/sequences.py Outdated Show resolved Hide resolved
Copy link
Collaborator

@benhoyt benhoyt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I haven't done a super-close look, but I've scanned over the whole thing, and this looks good to me. I quite like how it looks, and the implementation is significantly simpler.

README.md Outdated Show resolved Hide resolved
The failing test are (a) ones that need to be rewritten for the new system, (b) ones to do with custom events.
@tonyandrewmeyer tonyandrewmeyer merged commit e543303 into canonical:7.0 Jun 6, 2024
2 checks passed
@tonyandrewmeyer tonyandrewmeyer deleted the events-on-on branch June 6, 2024 06:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants