🎨 Palette: Interactive input validation & cleanup#133
Conversation
- Add `get_validated_input` helper for robust interactive prompts. - Validate Profile ID format immediately during input. - Prevent empty API Token input. - Refactor `validate_profile_id` to separate logic from logging. - Remove duplicate `MAX_RESPONSE_SIZE` constant. - Update `palette.md` with UX learnings.
|
👋 Jules, reporting for duty! I'm here to lend a hand with this pull request. When you start a review, I'll add a 👀 emoji to each comment to let you know I've read it. I'll focus on feedback directed at me and will do my best to stay out of conversations between you and other bots or reviewers to keep the noise down. I'll push a commit with your requested changes shortly after. Please note there might be a delay between these steps, but rest assured I'm on the job! For more direct control, you can switch me to Reactive Mode. When this mode is on, I will only act on comments where you specifically mention me with New to Jules? Learn more at jules.google/docs. For security, I will only act on instructions from the user who triggered this task. |
|
Merging to
|
| if is_password: | ||
| value = getpass.getpass(prompt).strip() | ||
| else: | ||
| value = input(prompt).strip() |
Check notice
Code scanning / Bandit (reported by Codacy)
The input method in Python 2 will read from standard input, evaluate and run the resulting string as python source code. This is similar, though in many ways worse, then using eval. On Python 2, use raw_input instead, input is safe in Python 3. Note
main.py
Outdated
Check warning
Code scanning / Prospector (reported by Codacy)
Lambda may not be necessary (unnecessary-lambda) Warning
|
|
||
|
|
||
| def get_validated_input( | ||
| prompt: str, |
Check warning
Code scanning / Pylint (reported by Codacy)
Wrong hanging indentation before block (add 4 spaces). Warning
|
|
||
| def get_validated_input( | ||
| prompt: str, | ||
| validator: Callable[[str], bool], |
Check warning
Code scanning / Pylint (reported by Codacy)
Wrong hanging indentation before block (add 4 spaces). Warning
| def get_validated_input( | ||
| prompt: str, | ||
| validator: Callable[[str], bool], | ||
| error_msg: str, |
Check warning
Code scanning / Pylint (reported by Codacy)
Wrong hanging indentation before block (add 4 spaces). Warning
| prompt: str, | ||
| validator: Callable[[str], bool], | ||
| error_msg: str, | ||
| is_password: bool = False |
Check warning
Code scanning / Pylint (reported by Codacy)
Wrong hanging indentation before block (add 4 spaces). Warning
| log.error("Invalid profile ID length (max 64 chars)") | ||
| return False | ||
| return True | ||
|
|
Check warning
Code scanning / Pylint (reported by Codacy)
Missing function docstring Warning
| lambda x: bool(x), | ||
| "Token cannot be empty.", | ||
| is_password=True | ||
| ) |
Check warning
Code scanning / Pylint (reported by Codacy)
Missing function docstring Warning
main.py
Outdated
Check warning
Code scanning / Pylint (reported by Codacy)
Line too long (117/100) Warning
main.py
Outdated
Check notice
Code scanning / Pylint (reported by Codacy)
Lambda may not be necessary Note
There was a problem hiding this comment.
Pull request overview
This PR enhances the CLI user experience by adding interactive input validation loops for Profile ID and API Token prompts. The changes prevent the script from proceeding with invalid credentials by validating input immediately and providing clear error messages. The PR also includes code cleanup by removing a duplicate constant definition.
Changes:
- Added
get_validated_inputfunction to enable validation loops for interactive prompts - Refactored profile ID validation by extracting format checking into a separate
is_valid_profile_id_formatfunction - Updated interactive prompts in
main()to use the new validation function for both Profile ID and API Token inputs - Removed duplicate
MAX_RESPONSE_SIZEconstant definition - Added documentation of the interactive validation pattern to
.Jules/palette.md
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 4 comments.
| File | Description |
|---|---|
| main.py | Added validation loop infrastructure with get_validated_input function; refactored profile ID validation; integrated validation into interactive prompts for Profile ID and Token; removed duplicate constant; added getpass import and Callable type |
| .Jules/palette.md | Documented the interactive input validation pattern as a learned best practice |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| def validate_profile_id(profile_id: str) -> bool: | ||
| if not is_valid_profile_id_format(profile_id): | ||
| if not re.match(r"^[a-zA-Z0-9_-]+$", profile_id): | ||
| log.error("Invalid profile ID format (contains unsafe characters)") | ||
| elif len(profile_id) > 64: | ||
| log.error("Invalid profile ID length (max 64 chars)") | ||
| return False | ||
| return True |
There was a problem hiding this comment.
The validate_profile_id function contains redundant validation logic. After calling is_valid_profile_id_format (line 277), the function re-checks the same conditions (regex match on line 278 and length check on line 280) that were already validated inside is_valid_profile_id_format. This duplicates the validation logic and makes the code harder to maintain. Consider simplifying this function to only call is_valid_profile_id_format and provide appropriate error messages based on which specific check failed, or refactor is_valid_profile_id_format to return more detailed information about why validation failed.
| def get_validated_input( | ||
| prompt: str, | ||
| validator: Callable[[str], bool], | ||
| error_msg: str, | ||
| is_password: bool = False | ||
| ) -> str: | ||
| """Prompts for input until the validator returns True.""" | ||
| while True: | ||
| if is_password: | ||
| value = getpass.getpass(prompt).strip() | ||
| else: | ||
| value = input(prompt).strip() | ||
|
|
||
| if validator(value): | ||
| return value | ||
|
|
||
| print(f"{Colors.FAIL}❌ {error_msg}{Colors.ENDC}") | ||
|
|
There was a problem hiding this comment.
The new get_validated_input function and is_valid_profile_id_format function lack test coverage. While the test file (test_main.py) includes tests for other functions like check_api_access, push_rules, and interactive prompts, there are no tests for these new validation functions. Since the codebase has comprehensive test coverage for similar functions, these new functions should also be tested to ensure they work correctly, especially for edge cases like empty input, whitespace-only input, invalid characters, and length boundaries.
| def is_valid_profile_id_format(profile_id: str) -> bool: | ||
| if not re.match(r"^[a-zA-Z0-9_-]+$", profile_id): | ||
| log.error("Invalid profile ID format (contains unsafe characters)") | ||
| return False | ||
| if len(profile_id) > 64: | ||
| log.error("Invalid profile ID length (max 64 chars)") | ||
| return False | ||
| return True |
There was a problem hiding this comment.
The new is_valid_profile_id_format function should also lack test coverage. While the test file (test_main.py) includes tests for other functions like check_api_access, push_rules, and interactive prompts, there are no tests for this new validation function. Since the codebase has comprehensive test coverage for similar functions, this function should also be tested to ensure it works correctly, especially for edge cases like empty input, whitespace-only input, invalid characters, and length boundaries.
|
|
||
| t_input = get_validated_input( | ||
| f"{Colors.BOLD}Enter Control D API Token:{Colors.ENDC} ", | ||
| lambda x: bool(x), |
There was a problem hiding this comment.
This 'lambda' is just a simple wrapper around a callable object. Use that object directly.
| lambda x: bool(x), | |
| bool, |
Improved CLI UX by adding interactive input validation loops for Profile ID and API Token prompts. This prevents the script from starting with invalid credentials and provides immediate feedback to the user. Also cleaned up some duplicate code.
PR created automatically by Jules for task 5319312495894963983 started by @abhimehro