From 37c957cc650f60b399fbdb89a92b1a76f04204a6 Mon Sep 17 00:00:00 2001 From: Axy Date: Mon, 19 Jan 2026 15:51:08 +0100 Subject: [PATCH] Add solution for exercises 0 to 5 --- .gitignore | 4 ++ ex0/ft_first_exception.py | 39 ++++++++++++ ex1/ft_different_errors.py | 53 +++++++++++++++++ ex2/ft_custom_errors.py | 52 ++++++++++++++++ ex3/ft_finally_block.py | 33 +++++++++++ ex4/ft_raise_errors.py | 64 ++++++++++++++++++++ ex5/ft_garden_management.py | 115 ++++++++++++++++++++++++++++++++++++ 7 files changed, 360 insertions(+) create mode 100644 .gitignore create mode 100644 ex0/ft_first_exception.py create mode 100644 ex1/ft_different_errors.py create mode 100644 ex2/ft_custom_errors.py create mode 100644 ex3/ft_finally_block.py create mode 100644 ex4/ft_raise_errors.py create mode 100644 ex5/ft_garden_management.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7a6cd49 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +__pycache__/ +*.pdf +*.txt +.gemini/ diff --git a/ex0/ft_first_exception.py b/ex0/ft_first_exception.py new file mode 100644 index 0000000..61787ca --- /dev/null +++ b/ex0/ft_first_exception.py @@ -0,0 +1,39 @@ +def check_temperature(temp_str: str) -> int | None: + """ + Checks if the temperature is valid for plants (0-40). + Returns the temperature if valid, None otherwise. + """ + try: + temp = int(temp_str) + if temp < 0: + print(f"Error: {temp}°C is too cold for plants (min 0°C)") + return None + elif temp > 40: + print(f"Error: {temp}°C is too hot for plants (max 40°C)") + return None + else: + return temp + except ValueError: + print(f"Error: '{temp_str}' is not a valid number") + return None + + +def test_temperature_input() -> None: + """ + Demonstrates testing with various inputs. + """ + print("=== Garden Temperature Checker ===") + + inputs = ["25", "abc", "100", "-50"] + + for inp in inputs: + print(f"Testing temperature: {inp}") + result = check_temperature(inp) + if result is not None: + print(f"Temperature {result}°C is perfect for plants!") + + print("All tests completed - program didn't crash!") + + +if __name__ == "__main__": + test_temperature_input() diff --git a/ex1/ft_different_errors.py b/ex1/ft_different_errors.py new file mode 100644 index 0000000..a6f88b1 --- /dev/null +++ b/ex1/ft_different_errors.py @@ -0,0 +1,53 @@ +def garden_operations() -> None: + """ + Demonstrates handling of different exception types in garden operations. + """ + print("=== Garden Error Types Demo ===") + + # ValueError + print("Testing ValueError...") + try: + int("abc") + except ValueError as e: + print(f"Caught ValueError: {e}") + + # ZeroDivisionError + print("Testing ZeroDivisionError...") + try: + 10 / 0 + except ZeroDivisionError as e: + print(f"Caught ZeroDivisionError: {e}") + + # FileNotFoundError + print("Testing FileNotFoundError...") + try: + open("missing.txt", "r") + except FileNotFoundError: + print("Caught FileNotFoundError: No such file 'missing.txt'") + + # KeyError + print("Testing KeyError...") + try: + d = {} + _ = d["missing_plant"] + except KeyError as e: + print(f"Caught KeyError: {e}") + + # Multiple errors + print("Testing multiple errors together...") + try: + int("abc") + except (ValueError, ZeroDivisionError): + print("Caught an error, but program continues!") + + +def test_error_types() -> None: + """ + Runs the garden operations demonstration. + """ + garden_operations() + print("All error types tested successfully!") + + +if __name__ == "__main__": + test_error_types() diff --git a/ex2/ft_custom_errors.py b/ex2/ft_custom_errors.py new file mode 100644 index 0000000..1917cd5 --- /dev/null +++ b/ex2/ft_custom_errors.py @@ -0,0 +1,52 @@ +class GardenError(Exception): + """Base class for garden-related errors.""" + + pass + + +class PlantError(GardenError): + """Error related to plants.""" + + pass + + +class WaterError(GardenError): + """Error related to watering.""" + + pass + + +def test_custom_errors() -> None: + """ + Demonstrates raising and catching custom exceptions. + """ + print("=== Custom Garden Errors Demo ===") + + print("Testing PlantError...") + try: + raise PlantError("The tomato plant is wilting!") + except PlantError as e: + print(f"Caught PlantError: {e}") + + print("Testing WaterError...") + try: + raise WaterError("Not enough water in the tank!") + except WaterError as e: + print(f"Caught WaterError: {e}") + + print("Testing catching all garden errors...") + try: + raise PlantError("The tomato plant is wilting!") + except GardenError as e: + print(f"Caught a garden error: {e}") + + try: + raise WaterError("Not enough water in the tank!") + except GardenError as e: + print(f"Caught a garden error: {e}") + + print("All custom error types work correctly!") + + +if __name__ == "__main__": + test_custom_errors() diff --git a/ex3/ft_finally_block.py b/ex3/ft_finally_block.py new file mode 100644 index 0000000..de5d73b --- /dev/null +++ b/ex3/ft_finally_block.py @@ -0,0 +1,33 @@ +def water_plants(plant_list: list) -> None: + """ + Waters plants in the list, ensuring cleanup happens. + """ + try: + print("Opening watering system") + for plant in plant_list: + if not isinstance(plant, str): + raise TypeError(f"Cannot water {plant} - invalid plant!") + print(f"Watering {plant}") + except TypeError as e: + print(f"Error: {e}") + finally: + print("Closing watering system (cleanup)") + + +def test_watering_system() -> None: + """ + Tests the watering system with valid and invalid lists. + """ + print("=== Garden Watering System ===") + + print("Testing normal watering...") + water_plants(["tomato", "lettuce", "carrots"]) + print("Watering completed successfully!") + + print("Testing with error...") + water_plants(["tomato", None, "carrots"]) + print("Cleanup always happens, even with errors!") + + +if __name__ == "__main__": + test_watering_system() diff --git a/ex4/ft_raise_errors.py b/ex4/ft_raise_errors.py new file mode 100644 index 0000000..f9e66ba --- /dev/null +++ b/ex4/ft_raise_errors.py @@ -0,0 +1,64 @@ +def check_plant_health( + plant_name: str, water_level: int, sunlight_hours: int +) -> str: + """ + Checks if plant parameters are within valid ranges. + Raises ValueError if not. + """ + if not plant_name: + raise ValueError("Plant name cannot be empty!") + + if water_level < 1 or water_level > 10: + if water_level > 10: + raise ValueError(f"Water level {water_level} is too high (max 10)") + else: + raise ValueError(f"Water level {water_level} is too low (min 1)") + + if sunlight_hours < 2 or sunlight_hours > 12: + if sunlight_hours < 2: + raise ValueError( + f"Sunlight hours {sunlight_hours} is too low (min 2)" + ) + else: + raise ValueError( + f"Sunlight hours {sunlight_hours} is too high (max 12)" + ) + + return f"Plant '{plant_name}' is healthy!" + + +def test_plant_checks() -> None: + """ + Tests plant health check with various invalid inputs. + """ + print("=== Garden Plant Health Checker ===") + + print("Testing good values...") + try: + print(check_plant_health("tomato", 5, 8)) + except ValueError as e: + print(f"Error: {e}") + + print("Testing empty plant name...") + try: + check_plant_health("", 5, 8) + except ValueError as e: + print(f"Error: {e}") + + print("Testing bad water level...") + try: + check_plant_health("lettuce", 15, 8) + except ValueError as e: + print(f"Error: {e}") + + print("Testing bad sunlight hours...") + try: + check_plant_health("carrot", 5, 0) + except ValueError as e: + print(f"Error: {e}") + + print("All error raising tests completed!") + + +if __name__ == "__main__": + test_plant_checks() diff --git a/ex5/ft_garden_management.py b/ex5/ft_garden_management.py new file mode 100644 index 0000000..731e95d --- /dev/null +++ b/ex5/ft_garden_management.py @@ -0,0 +1,115 @@ +class GardenError(Exception): + """Base class for garden-related errors.""" + + pass + + +class PlantError(GardenError): + """Error related to plants.""" + + pass + + +class WaterError(GardenError): + """Error related to watering.""" + + pass + + +class GardenManager: + """ + Manages a garden with resilient error handling. + """ + + def __init__(self): + self.plants = [] + + def add_plant(self, name: str) -> None: + """ + Adds a plant to the garden. + Raises PlantError if name is invalid. + """ + if not name: + raise PlantError("Plant name cannot be empty!") + self.plants.append(name) + print(f"Added {name} successfully") + + def water_plants(self) -> None: + """ + Waters all plants in the garden. + Uses finally block for cleanup. + """ + print("Opening watering system") + try: + for plant in self.plants: + print(f"Watering {plant} - success") + except Exception as e: + print(f"Error watering: {e}") + finally: + print("Closing watering system (cleanup)") + + def check_plant_health( + self, name: str, water_level: int, sun_hours: int + ) -> None: + """ + Checks health of a plant. + Raises GardenError (or subclasses) if conditions are bad. + """ + try: + if name not in self.plants: + raise PlantError(f"Plant {name} not in garden") + + if water_level < 0 or water_level > 10: + if water_level > 10: + raise WaterError( + f"Water level {water_level} is too high (max 10)" + ) + else: + raise WaterError( + f"Water level {water_level} is too low (min 0)" + ) + + if sun_hours < 0: + raise GardenError("Sunlight cannot be negative") + + print(f"{name}: healthy (water: {water_level}, sun: {sun_hours})") + + except GardenError as e: + print(f"Error checking {name}: {e}") + + +def test_garden_management() -> None: + """ + Demonstrates the full garden management system. + """ + print("=== Garden Management System ===") + manager = GardenManager() + + print("Adding plants to garden...") + try: + manager.add_plant("tomato") + manager.add_plant("lettuce") + manager.add_plant("") + except PlantError as e: + print(f"Error adding plant: {e}") + + print("Watering plants...") + manager.water_plants() + + print("Checking plant health...") + manager.check_plant_health("tomato", 5, 8) + manager.check_plant_health("lettuce", 15, 8) + + print("Testing error recovery...") + try: + # Simulate a critical error condition we want to catch explicitly + raise GardenError("Not enough water in tank") + except GardenError as e: + print(f"Caught GardenError: {e}") + print("System recovered and continuing...") + + print("Garden management system test complete!") + + +if __name__ == "__main__": + test_garden_management() -- 2.52.0