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

Use click features for project creation prompts #4387

Open
wants to merge 31 commits into
base: main
Choose a base branch
from

Conversation

lrcouto
Copy link
Contributor

@lrcouto lrcouto commented Dec 17, 2024

Description

Replaces Cookiecutter prompts with the click.prompt method, without affecting functionality in kedro new.
We are still using some methods that Cookiecutter imports from Rich, mainly for exceptions, so at the moment it'll still not allow us to uninstall rich without downgrading Cookiecutter.

Prompt appearance is now defined used the click.style method, so it can be changed if we so desire.
Example appearance:

image

Development notes

Developer Certificate of Origin

We need all contributions to comply with the Developer Certificate of Origin (DCO). All commits must be signed off by including a Signed-off-by line in the commit message. See our wiki for guidance.

If your PR is blocked due to unsigned commits, then you must follow the instructions under "Rebase the branch" on the GitHub Checks page for your PR. This will retroactively add the sign-off to all unsigned commits and allow the DCO check to pass.

Checklist

  • Read the contributing guidelines
  • Signed off each commit with a Developer Certificate of Origin (DCO)
  • Opened this PR as a 'Draft Pull Request' if it is work-in-progress
  • Updated the documentation to reflect the code changes
  • Added a description of this change in the RELEASE.md file
  • Added tests to cover my changes
  • Checked if this change will affect Kedro-Viz, and if so, communicated that with the Viz team

Signed-off-by: Laura Couto <[email protected]>
Signed-off-by: Laura Couto <[email protected]>
Signed-off-by: Laura Couto <[email protected]>
@lrcouto
Copy link
Contributor Author

lrcouto commented Dec 17, 2024

The current problem with this is that when the --starter flag is used, the prompts are supposed to be different. By using the click prompt feature, the default prompts are evaluated before we have the chance to check if a starter is being used or not. I will see if there's any way to get around this issue.

@astrojuanlu
Copy link
Member

I confirm that the current branch works at least!

image

IIUC this now purely uses Click. Is there a plan to try to restore the colors later on, maybe using https://click.palletsprojects.com/en/stable/utils/#ansi-colors ? (not necessarily right now, as it would probably complicate fixing the remaining tests)

@lrcouto
Copy link
Contributor Author

lrcouto commented Jan 14, 2025

IIUC this now purely uses Click. Is there a plan to try to restore the colors later on, maybe using https://click.palletsprojects.com/en/stable/utils/#ansi-colors ? (not necessarily right now, as it would probably complicate fixing the remaining tests)

Definitely! I want to make sure all of the functionality is as we expect first, but it would be nice to have an option for colors (with the added bonus of not relying on Rich)

@lrcouto lrcouto marked this pull request as ready for review January 16, 2025 14:28
@lrcouto lrcouto requested a review from merelcht as a code owner January 16, 2025 14:28
@ElenaKhaustova
Copy link
Contributor

@lrcouto, could you please clarify if colours should work and how we can check everything works as expected?

@lrcouto
Copy link
Contributor Author

lrcouto commented Jan 16, 2025

@lrcouto, could you please clarify if colours should work and how we can check everything works as expected?

They do not work yet, I'm implementing a color scheme at the moment.

It should not affect automated tests, but the visual appearance will also be slightly different, as those prompts from cookiecutter were importing the Prompt class from Rich. I'll post some screenshots with options once I finish implementing it.

@lrcouto
Copy link
Contributor Author

lrcouto commented Jan 16, 2025

Could look somewhat like this, for example:

image

Copy link
Member

@merelcht merelcht left a 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 a good start of removing some cookiecutter functionality, but like mentioned in the ticket:

These could be used to get rid of/simplify the validation we do for inputs to kedro new options like --tools and --example

I think it would be good to try and simplify the validation/prompting logic by using click functionality.

show_default=True,
type=str,
).strip()

if user_input:
prompt.validate(user_input)
Copy link
Member

Choose a reason for hiding this comment

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

Do we still need to use our own custom validation or is it possible to use click for that as well? I saw that was one of the suggestions on the original ticket #3878

Copy link
Member

Choose a reason for hiding this comment

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

Especially lower down in the code we have pretty complex parsing/validation methods e.g. _parse_tools_input.

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'm looking into this right now. From what I had seen I think the options that click has might be a bit unspecific for what we need, but there's an option to apply custom validation logic.

Copy link
Member

Choose a reason for hiding this comment

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

Yes for the more complicated options it might not be possible, but for --example and --telemetry we only need to check yes/no/y/n. I think you can do something like:

@click.option(
    "--example",
    "-e",
    "example_pipeline",
    help=EXAMPLE_ARG_HELP,
    type=click.Choice(["yes", "no", "y", "n"], case_sensitive=False),
)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

That does work for yes/no options. One minor issue though is that the error message is not customizable though. On top of that, the example pipeline option received through a config file would still need to have some validation since it doesn't go through the CLI options, so we'd still need the function.

This is what the error message from click.Choice looks like:

image

As opposed to the one we have right now, from _validate_input_with_regex_pattern:

image

For interactive prompts, that are happening inside a loop, there would need to be some sort of logic to pass the click.Choice value for the different prompts. Could be done through the prompts.yml file maybe.

Copy link
Contributor Author

@lrcouto lrcouto Jan 20, 2025

Choose a reason for hiding this comment

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

For that specific validate we could use one of the click Exception options, though I feel like they were more designed to be used with CLI options and not with prompts. I also personally like having finer control over the appearance of the error messages.

(Also, could we maybe move this user_input parameter to be inside the _Prompt class and validate it as we set it? The function is called only once, I don't think it necessarily needs to be a function)

Copy link
Contributor Author

@lrcouto lrcouto Jan 21, 2025

Choose a reason for hiding this comment

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

Another possibility is using the callback parameter in click for custom validation. For example, this:

def _validate_yes_no(ctx, param, value) -> None:
    if not re.match(r"(?i)^\s*(y|yes|n|no)\s*$", value, flags=re.X):
        raise click.BadParameter(f"'{value}' is an invalid value for {param}. It must contain only y, n, YES, or NO (case insensitive).")
    return value
    
    @click.option("--telemetry", "-tc", "telemetry_consent", help=TELEMETRY_ARG_HELP, callback=_validate_yes_no)

Results in this:

image

Does require writing the callback functions though. And the output is the click Exception output.

Copy link
Member

Choose a reason for hiding this comment

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

I personally think the default click exception ("Invalid value for..") is fine. But maybe @astrojuanlu has a different view on that.

Copy link
Member

Choose a reason for hiding this comment

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

I agree the default click exception is fine, considering the tradeoffs

"-t",
"selected_tools",
help=TOOLS_ARG_HELP,
)
@click.option("--example", "-e", "example_pipeline", help=EXAMPLE_ARG_HELP)
Copy link
Member

Choose a reason for hiding this comment

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

Can you use Click choice options here https://click.palletsprojects.com/en/stable/options/#choice-options to simplify the prompting and validation logic for example project?

@lrcouto
Copy link
Contributor Author

lrcouto commented Jan 22, 2025

After some exploration of the project creation flow (colloquially referred to as "gazing into the abyss") with the objective of simplifying it in some way, shape or form, we can extract some insights:

  • The main complication of the project creation flow is that we can get user input in three different ways: through the CLI, throught prompts, or through a config file. This makes input validation a little tricky, because as of now we're having to validate it in several different points of the new function, which feels confusing to read.
  • On top of that, tools validation is particulary confusing because the input is different depending on the source. Sometimes it's numbers. Sometimes it's names. Sometimes it's a string. Sometimes it's a list. The data is converted from one format to the other multiple times throughout the project creation flow and it's easy to lose track of which is which.
  • That said, changing the prompts themselves to using Click's instead of Cookiecutter's was doable without affecting functionality. The appearance is different, but the upside is that we have more control over it.
  • ...which is one step in the direction of being able to run kedro new without having Rich installed, though more work need to be done on that. Changing our own prompts is not going to be enough, because we are using Cookiecutters git cloning function and it imports the rich.prompt library. Even though we are using the function with its no_input option, it still tries to import the lib and will break if it does not find it.

For now what could be done, besides the aforementioned replacement of the prompts, is replacing the --telemetry CLI input validation with the click.Choice option (which prevents an incorrect error message to be displayed if the input is bad, it was treating it as if it was the --example flag), and doing some cleaning up on the _Prompt class.

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.

Use click choice options to simplify validation of project creation workflow
4 participants