Repository: kedro-org/kedro

Issue:
Kedro new starter CLI : user_input.lower()
## Description
I use kedro starter CLI configured by prompt.yml with regex check and I think I found one issue : the user inputs are systematically transformed to lowercase : https://github.com/kedro-org/kedro/blob/main/kedro/framework/cli/starters.py#L957
The result is that I can't restrict user input to uppercase or lowercase

## Context
I want to restrict user input to uppercase

## Steps to Reproduce
1. create a cookiecutter template for kedro (regarding your need)
2. create your cookiecutter.json with `project_name` as unique prompt
3. create your prompt.yml with an entry for `project_name`
4. set the `regex_validator` field to `"[A-Z_]+"`
5. start `kedro new --starter=./my_starter` and answer `MY_PROJECT` for `project_name` prompt
6. It will fail due to the  `user_input.lower()` in `kedro/framework/cli/starters.py` line 957

## Expected Result
The regex and the input must match

## Actual Result
The user input is refused

## Your Environment
Python : 3.9.13
Kedro : 0.19.3
OS : Linux (distribution and kernel version confidential)



Discussion:
I think that is by design that we don't allow upper case. As I understand this is the convention for Python community. 

https://gist.github.com/etigui/7600441926e73c3385057718c2fdef8e

However the error may not be clear enough, curious if you are creating your own starters?

I know about python naming convention, the point is not here : the regex of prompt for project name in uppercase was just for the example.
In reality I use the regex for a variable value in the project which needs to be in uppercase, your code is clear : you apply lower() method on the user input which is not correct.
@lpsedo got it, would you like to send a PR to fix this? It should be a relative simple one happy to merge this. 
Sure, I will potentially make the PR this weekend
Hi @Ipsedo are you still interested in creating a PR for this? 
@merelcht I would like to work on this - do I need to be assigned first or should I submit a PR directly? 

Hi @parthmshah1302, thanks for helping out! You can just go ahead and create a PR when you're ready 🙂 
Hi, could I please get a status update on this? I’d like to work on it if possible.
Hi @AdityaS8804, the ticket is still open, so you can just go ahead and create a PR when you're ready 🙂
Summary:

The docs say that starter creators can add their own variables with custom `regex_validator`:

https://docs.kedro.org/en/stable/starters/create_a_starter.html#custom-project-creation-variables

but Kedro is not allowing uppercase letters even in variables:

https://github.com/kedro-org/kedro/blob/87773e85a4ac9e06e3c6b83461a6ffe9510cf7d3/kedro/framework/cli/starters.py#L957

Future takers of this issue: don't ask for permission, just go ahead and open a PR. If you need clarification about the problem, don't hesitate to ask.



Patch:
diff --git a/RELEASE.md b/RELEASE.md
index f141c29aef..49fb42d94c 100644
--- a/RELEASE.md
+++ b/RELEASE.md
@@ -12,10 +12,13 @@
 * Update error message when executing kedro run without pipeline.
 * Safeguard hooks when user incorrectly registers a hook class in settings.py.
 * Fixed parsing paths with query and fragment.
+* Remove lowercase transformation in regex validation.
 
 ## Breaking changes to the API
 ## Documentation changes
+
 ## Community contributions
+* [Hendrik Scherner](https://github.com/SchernHe)
 
 # Release 0.19.10
 
diff --git a/kedro/framework/cli/starters.py b/kedro/framework/cli/starters.py
index f7082311db..0d3b54c8ec 100644
--- a/kedro/framework/cli/starters.py
+++ b/kedro/framework/cli/starters.py
@@ -1005,8 +1005,7 @@ def __str__(self) -> str:
 
     def validate(self, user_input: str) -> None:
         """Validate a given prompt value against the regex validator"""
-
-        if self.regexp and not re.match(self.regexp, user_input.lower()):
+        if self.regexp and not re.match(self.regexp, user_input):
             message = f"'{user_input}' is an invalid value for {(self.title).lower()}."
             click.secho(message, fg="red", err=True)
             click.secho(self.error_message, fg="red", err=True)
diff --git a/kedro/templates/project/prompts.yml b/kedro/templates/project/prompts.yml
index c6f8608b28..a4f7621464 100644
--- a/kedro/templates/project/prompts.yml
+++ b/kedro/templates/project/prompts.yml
@@ -26,7 +26,7 @@ tools:
     7) Kedro-Viz: Kedro's native visualisation tool
 
     Which tools would you like to include in your project? [1-7/1,3/all/none]:
-  regex_validator: "^(all|none|(( )*\\d+( *- *\\d+)?( *, *\\d+( *- *\\d+)?)*( )*)?)$"
+  regex_validator: "(?i)^(all|none|(( )*\\d+( *- *\\d+)?( *, *\\d+( *- *\\d+)?)*( )*)?)$"
   error_message: |
     Invalid input. Please select valid options for project tools using comma-separated values, ranges, or 'all/none'.
 


Test patch:
diff --git a/tests/framework/cli/test_starters.py b/tests/framework/cli/test_starters.py
index 87c434dfd1..a1852c75af 100644
--- a/tests/framework/cli/test_starters.py
+++ b/tests/framework/cli/test_starters.py
@@ -422,7 +422,15 @@ def test_empty_prompts(self, fake_kedro_cli):
         _assert_template_ok(result)
         _clean_up_project(Path("./new-kedro-project"))
 
-    def test_custom_prompt_valid_input(self, fake_kedro_cli):
+    @pytest.mark.parametrize(
+        "regex, valid_value",
+        [
+            ("^\\w+(-*\\w+)*$", "my-value"),
+            ("^[A-Z_]+", "MY-VALUE"),
+            ("^\\d+$", "123"),
+        ],
+    )
+    def test_custom_prompt_valid_input(self, fake_kedro_cli, regex, valid_value):
         shutil.copytree(TEMPLATE_PATH, "template")
         _write_yaml(
             Path("template") / "prompts.yml",
@@ -430,11 +438,11 @@ def test_custom_prompt_valid_input(self, fake_kedro_cli):
                 "project_name": {"title": "Project Name"},
                 "custom_value": {
                     "title": "Custom Value",
-                    "regex_validator": "^\\w+(-*\\w+)*$",
+                    "regex_validator": regex,
                 },
             },
         )
-        custom_input = "\n".join(["my-project", "My Project"])
+        custom_input = "\n".join([valid_value, "My Project"])
         result = CliRunner().invoke(
             fake_kedro_cli,
             ["new", "--starter", "template"],
@@ -446,6 +454,7 @@ def test_custom_prompt_valid_input(self, fake_kedro_cli):
             repo_name="my-project",
             python_package="my_project",
         )
+
         _clean_up_project(Path("./my-project"))
 
     def test_custom_prompt_for_essential_variable(self, fake_kedro_cli):