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

[Tidy] Convert actions to classes #363

Draft
wants to merge 27 commits into
base: dev/actions_v2
Choose a base branch
from

Conversation

petar-qb
Copy link
Contributor

@petar-qb petar-qb commented Mar 12, 2024

Description

For those who will review this PR:

Here is a small recommendation on how to familiarise yourself with the PR changes in the fastest way and how to review the PR. It is only a recommendation and feel free to skip some of the suggested steps if you are already familiar with them or if you are not interested in them.

  1. Don't rush to review the changes right away.
  2. Read the entire PR description.
  3. Watch the Team Learning session.
  4. Run all examples in vizro-core/examples/_dev/ folder. They are already sorted alphabetically in the way they should run. For each example: read file docstrings, explore application configuration, and run and play with application UI.
  5. Investigate CapturedActionCallable → useful Gist that @antonymilne made: https://gist.github.com/antonymilne/174c4c49ace2dae1f1d7674183b8d140
    Link to the PS session -> https://mckinsey.box.com/s/fg1sdrpw6emprihhtg19ww4lft2ljma8
  6. Open and understand one of the action implementations (e.g. export_data_action)
  7. Search for TODO-AV2 and read everything. (especially since some "TODO-AV2" refer to multiple similar pieces of code, but are only written in one place)
  8. Start with discussing open questions ("TODO-AV2-OQ")
  9. Feel completely free to contribute:
    • Implementing some better architecture solutions,
    • Open any new kind of question.
    • Solving TODOs,
    • Cleaning the code,
    • Applying linting stuff,
    • Fixing/adding tests
    • Literally anything else
  10. Start with the standard code reviewing.

This PR is in the MVP phase because:

  • There are still some open questions that should be discussed.
  • The code is not completely tidied up.
  • tests, docs and linting is not completed.

The most important changes:

  • Implementation of class based action using CapturedActionCallable.
  • Actions validation and eager input arguments calculation.
  • Make filter_action and parameter_action public,
  • Change _on_page_load with a public update_figures action.
  • Expose Page.actions so it can be overwritten.
  • model_manager._get_model_page_id method improved

Bugfixes:

TODO-AV2 legend:

  • TODO-AV2 - I will solve these as the part of this PR,
  • TODO-AV2-OQ- Open Questions,
  • TODO-AV2-TICKET-CREATED - These will be solved as a separate PR, and the ticket for these is already created,
  • TODO-AV2-TICKET-NEW - These will be solved as a separate PR, and the following tickets have to be created,
  • *- tagged TODOs (contain the characters -*:) are candidate for solving by anyone from the team.

PR TODOs:

  • the final tidying up (getting rid of code duplications and some TODOs)
  • tests
  • docs

Notice

  • I acknowledge and agree that, by checking this box and clicking "Submit Pull Request":

    • I submit this contribution under the Apache 2.0 license and represent that I am entitled to do so on behalf of myself, my employer, or relevant third parties, as applicable.
    • I certify that (a) this contribution is my original creation and / or (b) to the extent it is not my original creation, I am authorized to submit this contribution on behalf of the original creator(s) or their licensees.
    • I certify that the use of this contribution as authorized by the Apache 2.0 license does not violate the intellectual property rights of anyone else.
    • I have not referenced individuals, products or companies in any commits, directly or indirectly.
    • I have not added data or restricted code in any commits, directly or indirectly.



class ExportDataClassAction(CapturedActionCallable):
def __init__(self, *args, **kwargs):
Copy link
Contributor

Choose a reason for hiding this comment

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

What's this __init__ for?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I used it to save input args and kwargs so they can be validated/adjusted in the _post_init.
Now, I got rid of the constructor and self._arguments is used inside the _post_init.

if self.inputs:
callback_inputs = [State(*input.split(".")) for input in self.inputs]
elif hasattr(self.function, "inputs") and self.function.inputs:
Copy link
Contributor

Choose a reason for hiding this comment

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

I guess we're going to have a few switches here while we have both the "old" function actions and the new class ones.

Let's have a consistent way of doing this everywhere to make it clearer. I think just isinstance(function, CapturedActionCallable) would work? No need to check if self.function.inputs is Falsey or not I think either.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I guess we're going to have a few switches here while we have both the "old" function actions and the new class ones.

You're right, and after all actions become implemented as CapturedActionCallable, then the following line will be removed:
else: callback_inputs = _get_action_callback_mapping(action_id=ModelID(str(self.id)), argument="inputs")


# Validate and calculate "targets"
targets = self._kwargs.get("targets")
if targets:
Copy link
Contributor

Choose a reason for hiding this comment

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

This feels like an improvement on the old function version because we now validate targets upfront rather than at runtime. Is that right?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yep, that's right! 😄

# Fake initialization - to let other actions see that this one exists.
super().__init__(*args, **kwargs)

def _post_init(self):
Copy link
Contributor

Choose a reason for hiding this comment

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

Should this be called directly in __init__ or is that too early?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It's too early to call _post_init validation inside the action initialisation phase. To be able to validate action input arguments properly, all dashboard models have to be initialised. Some of the models are initialised in the _pre_build phase of other models which means that the actions _post_init has to be called within the build phase.

raise ValueError(f"Component '{target}' does not exist on the page '{self._page_id}'.")
else:
targets = model_manager._get_page_model_ids_with_figure(page_id=self._page_id)
self._kwargs["targets"] = self.targets = targets
Copy link
Contributor

Choose a reason for hiding this comment

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

Not sure I understand what's happening with the _kwargs stuff here, please could you explain?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Now this line looks like this:
self._arguments["targets"] = self.targets = targets

  • targets - represents new validated and calculated action's targets
  • self._arguments["targets"] = targets - overwrites the pure_function input argument. Since the pure_function is a staticmethod (and I'm pretty sure it should remain), new calculated targets have to be propagated through the self._arguments.
  • self.targets = targets - Optionally, some of CapturedActionCallable attributes are also calculated in the _post_init phase. In this case, self.targets is created calculated so it can be easily reused inside the outputs and components` calculations.

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