-
-
Notifications
You must be signed in to change notification settings - Fork 469
Fix app name validation logic and improve error message #2405
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
base: main
Are you sure you want to change the base?
Changes from all commits
7c6cd96
cb8d9ee
e5727c7
f011119
982d2ec
02509a5
9d25586
925280f
7ce356d
615d177
aebdaab
43ee262
aab7c2b
cc36b4d
22c50b7
cea0991
37eae5e
820b0b5
fed1fe3
bdb07a8
79851d8
418a77a
4495ab4
849bc65
05f9444
29d2aa9
a4b4704
973bcc0
3957298
32e4277
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| Enhance app name validation to include additional checks for format and identifiers |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -107,17 +107,12 @@ def input_app_name(self, override_value: str | None) -> str: | |
| """ | ||
| intro = ( | ||
| "We need a name that can serve as a machine-readable Python package name for " | ||
| "your application. This name must be PEP508-compliant - that means the name " | ||
| "may only contain letters, numbers, hyphens and underscores; it can't contain " | ||
| "spaces or punctuation, and it can't start with a hyphen or underscore." | ||
| "your application. The name may only contain letters, numbers, hyphens and underscores; " | ||
| "it can't contain spaces or punctuation, and it can't start with a hyphen, underscore or a number." | ||
| ) | ||
|
|
||
| default = "hello-world" | ||
| if ( | ||
| "name" in self.pep621_data | ||
| and is_valid_app_name(self.pep621_data["name"]) | ||
| and override_value is None | ||
| ): | ||
| if "name" in self.pep621_data and override_value is None: | ||
| app_name = canonicalize_name(self.pep621_data["name"]) | ||
| self.console.divider(title="App name") | ||
| self.console.prompt() | ||
|
|
@@ -126,13 +121,36 @@ def input_app_name(self, override_value: str | None) -> str: | |
| ) | ||
| return app_name | ||
|
|
||
| if is_valid_app_name(self.base_path.name): # Directory name is normalised | ||
| default = canonicalize_name(self.base_path.name) | ||
| canonicalized_name = canonicalize_name(self.base_path.name) | ||
| # Case 1: Project name is usable as-is (e.g., "foobar", "foo-bar") | ||
| if ( | ||
| is_valid_app_name(self.base_path.name) | ||
| and canonicalized_name == self.base_path.name | ||
| ): | ||
| # Directory name is already valid - use it directly without prompting | ||
| if override_value is None: | ||
| self.console.divider(title="App name") | ||
| self.console.prompt() | ||
| self.console.prompt( | ||
| f"Using directory name as app name: {self.base_path.name!r}" | ||
| ) | ||
| return self.base_path.name | ||
| # If override_value is provided, fall through to prompt with it | ||
| default = self.base_path.name | ||
| intro += ( | ||
| "\n\n" | ||
| f"Based on your PEP508 formatted directory name, we suggest an " | ||
| f"app name of '{default}', but you can use another name if you want." | ||
| ) | ||
| # Case 2: Project name could be valid after canonicalization (e.g., "test.name" -> "test-name", "test-app_name" -> "test-app-name") | ||
| elif is_valid_app_name(canonicalized_name): | ||
| default = canonicalized_name | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. By this logic, case 1 and case 2 are functionally identical. The key difference between case 1 and case 2 is that we don't need to ask the user to confirm case 1 - we're using exactly the same name, so it's fine as is. Case 2 involves a transformation, so it needs to be confirmed.
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 |
||
| intro += ( | ||
| "\n\n" | ||
| f"Based on your directory name, we suggest an " | ||
| f"app name of '{default}', but you can use another name if you want." | ||
| ) | ||
| # Case 3: Project name isn't valid, even after canonicalization - fall back to default | ||
|
|
||
| return self.console.text_question( | ||
| intro=intro, | ||
|
|
||
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.
I'm not sure why you've dropped the validity check here -
1hello.worldis a validproject.nameby PEP 508, which canonicalizes to1hello-world- but that's not a valid app name, so it can't be used as a candidate.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.
I dropped it because otherwise I wouldn't be able to pass this test:
test.namefrom the [project] name in pyproject.toml isn’t a valid app name and therefore won’t be canonicalized totest-name.To be honest, I’m a bit confused right now about what I should do instead.
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.
There's 3 cases here:
foobarandfoo-barare both valid project names, and are also valid app names as-is. They can be directly provided as the candidate app name, as there's no transformation being applied.test.nameis a valid PEP 508 project name, and it canonicalizes totest-name; we don't want to provide that name as an automatic app name, but it's a reasonable candidate for an app name that the user could confirm as valid.42foobaris a valid project name - but it canonicalizes to exactly the same value, which isn't a valid app name. In this case, we need to fall back to other hinted options (such as the base path of the project).The code has a branch for 1 and 3; but the logic that triggers 1 is incorrect and it merges in the canonicalisation required by case 2. There's no logic handling the case of "test.name" being coerced into a hint for the user to confirm.
Does that make more sense?
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.
Yes, thank you for the explanation (and your patience 😅)
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.
Ok - but my the original point still stands: you've dropped the validation check on this branch. By this code, if user provides any value for
namein the[project]data, the canonicalised version of that name will be used. You've added code for the three cases that I described - but this check comes before those cases are evaluated.