|
4 | 4 |
|
5 | 5 | import logging |
6 | 6 | import sys |
| 7 | +from typing import Optional |
7 | 8 |
|
8 | 9 | logger = logging.getLogger(__name__) |
9 | 10 |
|
10 | | -# Define available snacks as a constant |
| 11 | +# Error message constants |
| 12 | +ERROR_MESSAGES = { |
| 13 | + "no_input": "No input provided", |
| 14 | + "interrupted": "User interrupted input", |
| 15 | + "no_data": "No input received", |
| 16 | + "invalid_choice": "Invalid snack choice", |
| 17 | +} |
| 18 | + |
11 | 19 | AVAILABLE_SNACKS = {"pizza", "pasta"} |
12 | 20 |
|
13 | 21 |
|
14 | | -def get_user_input() -> str: |
15 | | - """Get user input from console. |
| 22 | +class SnackSelectorError(Exception): |
| 23 | + """Base exception for snack selector errors.""" |
| 24 | + |
| 25 | + |
| 26 | +class InvalidInputError(SnackSelectorError): |
| 27 | + """Raised when user provides invalid input.""" |
16 | 28 |
|
17 | | - Returns: |
18 | | - str: User input in lowercase, or 'error' if invalid |
19 | | - """ |
| 29 | + def __init__(self, error_code: str): |
| 30 | + self.error_code = error_code |
| 31 | + messages = { |
| 32 | + "no_input": "No input provided", |
| 33 | + "interrupted": "User interrupted input", |
| 34 | + "no_data": "No input received", |
| 35 | + } |
| 36 | + super().__init__(messages.get(error_code, "Unknown input error")) |
| 37 | + |
| 38 | + |
| 39 | +def get_user_input() -> str: |
| 40 | + """Get user input from console.""" |
20 | 41 | try: |
21 | 42 | user_input = input("\nPlease provide your choice of snack: ") |
22 | | - # Better validation - check if input is not empty after stripping |
23 | 43 | cleaned_input = user_input.strip() |
24 | | - return cleaned_input.lower() if cleaned_input else "error" |
25 | | - except KeyboardInterrupt: |
26 | | - logger.info("\nGoodbye!") |
27 | | - sys.exit(0) |
28 | | - except EOFError: |
29 | | - logger.info("\nNo input received. Exiting...") |
30 | | - sys.exit(0) |
31 | 44 |
|
| 45 | + if not cleaned_input: |
| 46 | + raise InvalidInputError(ERROR_MESSAGES["no_input"]) |
32 | 47 |
|
33 | | -def is_snack_available(snack: str) -> bool: |
34 | | - """Check if the requested snack is available. |
| 48 | + return cleaned_input.lower() |
35 | 49 |
|
36 | | - Args: |
37 | | - snack: The snack to check |
| 50 | + except KeyboardInterrupt as e: |
| 51 | + raise InvalidInputError(ERROR_MESSAGES["interrupted"]) from e |
| 52 | + except EOFError as e: |
| 53 | + raise InvalidInputError(ERROR_MESSAGES["no_data"]) from e |
38 | 54 |
|
39 | | - Returns: |
40 | | - bool: True if snack is available, False otherwise |
41 | | - """ |
| 55 | + |
| 56 | +def is_snack_available(snack: str) -> bool: |
| 57 | + """Check if the requested snack is available.""" |
42 | 58 | return snack in AVAILABLE_SNACKS |
43 | 59 |
|
44 | 60 |
|
45 | | -def main(): |
| 61 | +def process_snack_request(snack: str) -> None: |
| 62 | + """Process the snack request and log the appropriate response.""" |
| 63 | + if is_snack_available(snack): |
| 64 | + logger.info("Here you go %s", snack) |
| 65 | + else: |
| 66 | + available_list = ", ".join(sorted(AVAILABLE_SNACKS)) |
| 67 | + logger.info("Sorry, we don't have %s in our menu. Available options: %s", snack, available_list) |
| 68 | + |
| 69 | + |
| 70 | +def main() -> None: |
46 | 71 | """Main function to run the snack selector.""" |
47 | 72 | logging.basicConfig( |
48 | 73 | level=logging.INFO, |
49 | 74 | format="%(asctime)s.%(msecs)03d - %(levelname)s - %(module)s:%(lineno)d - %(message)s", |
50 | 75 | datefmt="%Y-%m-%d %H:%M:%S", |
51 | 76 | ) |
52 | 77 |
|
53 | | - user_input = get_user_input() |
54 | | - |
55 | | - if user_input == "error": |
56 | | - logger.error("Invalid input provided. Exiting...") |
57 | | - sys.exit(1) # Use exit code 1 for error |
58 | | - elif is_snack_available(user_input): |
59 | | - logger.info("Here you go %s", user_input) |
60 | | - else: |
61 | | - logger.info("Sorry, we don't have %s in our menu. Please try something else.", user_input) |
| 78 | + try: |
| 79 | + user_input = get_user_input() |
| 80 | + process_snack_request(user_input) |
| 81 | + |
| 82 | + except InvalidInputError as e: |
| 83 | + logger.exception("Invalid input: %s", e) |
| 84 | + sys.exit(1) |
| 85 | + except Exception as e: |
| 86 | + logger.exception("Unexpected error: %s", e) |
| 87 | + sys.exit(1) |
62 | 88 |
|
63 | 89 |
|
64 | 90 | if __name__ == "__main__": |
|
0 commit comments