diff --git a/02/ex0/ft_first_exception.py b/02/ex0/ft_first_exception.py index 87b9bf6..32b43f2 100644 --- a/02/ex0/ft_first_exception.py +++ b/02/ex0/ft_first_exception.py @@ -1,5 +1,5 @@ -def check_temperature(temp_str: str) -> int: - print("Testing temperature:", temp_str) +def check_temperature(temp_str: str) -> int | None: + """Test if temperature is correct""" try: x = int(temp_str) if x > 40: @@ -8,20 +8,21 @@ def check_temperature(temp_str: str) -> int: raise Exception("is too cold for plants (min 0°C)") else: print("Temperature " + temp_str + "°C is perfect for plants!") + return x except ValueError: print("Error: '" + temp_str + "' is not a valid number") - pass except Exception as ex: print("Error: " + temp_str + "°C", ex) - pass + return (None) if __name__ == "__main__": + print("=== Garden Temperature checker ===") + print("\nTesting temperature: 25") check_temperature("25") - print("") + print("\nTesting temperature: abc") check_temperature("abc") - print("") + print("\nTesting temperature: 100") check_temperature("100") - print("") + print("\nTesting temperature: -50") check_temperature("-50") - print("") - print("All tests completed - program didn't crash!") + print("\nAll tests completed - program didn't crash!") diff --git a/02/ex1/ft_different_errors.py b/02/ex1/ft_different_errors.py index 4aefec7..35577ec 100644 --- a/02/ex1/ft_different_errors.py +++ b/02/ex1/ft_different_errors.py @@ -1,4 +1,5 @@ def garden_operations(case: str) -> None: + """Test some opereation case""" if case == "ValueError": int("abc") elif case == "ZeroDivisionError": @@ -11,26 +12,29 @@ def garden_operations(case: str) -> None: def test_error_types() -> None: + """Tester function to catch errors""" + print("=== Garden Error Types Demo ===") + print("\nTesting ValueError...") try: garden_operations("ValueError") except ValueError: print("Caught ValueError: invalid literal for int()") - + print("\nTesting ZeroDivisionError...") try: garden_operations("ZeroDivisionError") except ZeroDivisionError: print("Caught ZeroDivisionError: division by zero") - + print("\nTesting FileNotFoundError...") try: garden_operations("FileNotFoundError") except FileNotFoundError as err: print("Caught FileNotFoundError:", err) - + print("\nTesting KeyError...") try: garden_operations("KeyError") except KeyError as err: print("Caught KeyError:", err) - + print("\nTesting multiple errors together...") try: garden_operations("ValueError") except (ValueError, KeyError, ZeroDivisionError, FileNotFoundError): @@ -39,4 +43,4 @@ def test_error_types() -> None: if __name__ == "__main__": test_error_types() - print("All error types tested successfully!") + print("\nAll error types tested successfully!") diff --git a/02/ex2/ft_custom_errors.py b/02/ex2/ft_custom_errors.py index 5da19b2..a06b9ae 100644 --- a/02/ex2/ft_custom_errors.py +++ b/02/ex2/ft_custom_errors.py @@ -1,33 +1,53 @@ +from typing_extensions import override + + class GardenError(Exception): - def __init__(self, message): - self.message = message - - def __str__(self): + def __init__(self, message: str) -> None: + super().__init__() + self.message: str = message + + @override + def __str__(self) -> str: return f"Caught a garden error: {self.message}" class PlantError(GardenError): - def __init__(self, message): - self.message = message + def __init__(self, message: str) -> None: + super().__init__(message) - def __str__(self): + @override + def __str__(self) -> str: return f"Caught PlantError: {self.message}" class WaterError(GardenError): - def __init__(self, message): - self.message = message + def __init__(self, message: str) -> None: + super().__init__(message) - def __str__(self): + @override + def __str__(self) -> str: return f"Caught WaterError: {self.message}" if __name__ == "__main__": + print("=== Custom Garden Errors Demo ===") + print("\n Testing PlantError...") try: raise PlantError("The tomato plant is wilting!") except PlantError as err: print(err) + print("\nTesting WaterError...") try: raise WaterError("Not enough water in the tank!") except WaterError as err: print(err) + print("\nTesting catching all garden errors...") + try: + raise GardenError("The tomato plant is wilting") + except GardenError as err: + print(err) + try: + raise GardenError("Not enough water in the tank") + except GardenError as err: + print(err) + print("\nAll custom error types work correctly !") diff --git a/02/ex3/ft_finally_block.py b/02/ex3/ft_finally_block.py index 6673506..bf6e4f0 100644 --- a/02/ex3/ft_finally_block.py +++ b/02/ex3/ft_finally_block.py @@ -1,4 +1,5 @@ -def water_plants(plant_list: []) -> None: +def water_plants(plant_list: list[str | None]) -> None: + """Display watering plant if plant is a string""" for plant in plant_list: if plant == None: raise ValueError @@ -6,7 +7,10 @@ def water_plants(plant_list: []) -> None: def test_watering_system() -> None: + """Tester for water_plants() function""" plants = ["tomato", "lettuce", "carrots", None] + print("=== Garden Watering System ===") + print("\nTesting normal watering...") try: print("Opening watering system") water_plants(plants) @@ -14,6 +18,7 @@ def test_watering_system() -> None: print("Error: Cannot water None - invalid plant!") finally: print("Closing watering system (cleanup)") + print("\nCleanup always happens, even with errors") if __name__ == "__main__": diff --git a/02/ex4/ft_raise_errors.py b/02/ex4/ft_raise_errors.py index 243096d..5ea3d67 100644 --- a/02/ex4/ft_raise_errors.py +++ b/02/ex4/ft_raise_errors.py @@ -1,4 +1,4 @@ -def check_plant_health(plant_name, water_level, sunlight_hours): +def check_plant_health(plant_name: str, water_level: int, sunlight_hours: int) -> None: if not plant_name or not plant_name[0]: raise ValueError("Error: Plant name cannot be empty") elif water_level < 1: @@ -13,24 +13,29 @@ def check_plant_health(plant_name, water_level, sunlight_hours): print("Plant '" + plant_name + "' is healthy!") -def test_plant_checks(): +def test_plant_checks() -> None: + print("=== Garden Plant Health Checker ===") + print("\nTesting good values...") try: check_plant_health("tomato", 5, 5) except ValueError as err: print(err) + print("\nTesting bad water level...") try: check_plant_health("salade", 0, 5) except ValueError as err: print(err) + print("\nTesting bad sunlight hours...") try: check_plant_health("carrots", 5, 20) except ValueError as err: print(err) + print("\nTesting empty plant name...") try: check_plant_health("", 5, 5) except ValueError as err: print(err) - print("All error raising tests completed!") + print("\nAll error raising tests completed!") if __name__ == "__main__": diff --git a/02/ex5/ft_garden_management.py b/02/ex5/ft_garden_management.py index a4a9f8a..5907856 100644 --- a/02/ex5/ft_garden_management.py +++ b/02/ex5/ft_garden_management.py @@ -1,98 +1,170 @@ -from logging import raiseExceptions +from typing_extensions import override + + +class GardenError(Exception): + def __init__(self, message: str) -> None: + super().__init__() + self.message: str = message + + @override + def __str__(self) -> str: + return f"Caught a garden error: {self.message}" + + +class SunlightError(GardenError): + def __init__(self, message: str) -> None: + super().__init__(message) + + @override + def __str__(self) -> str: + return f"Caught SunlightError: {self.message}" + + +class WaterError(GardenError): + def __init__(self, message: str) -> None: + super().__init__(message) + + @override + def __str__(self) -> str: + return f"Caught WaterError: {self.message}" class Plant: __name: str - __water: int - __sun: int + __water_level: int + __sunlight_hours: int - @classmethod - def set_name(cls, name: str) -> None: - if not name or not name[0]: - raise ValueError("Name cannot be empty") - cls.__name = name - - @classmethod - def set_water(cls, water: int) -> None: - if water < 0: - raise ValueError("Water level cannot be negative") - cls.__water = water - - @classmethod - def set_sun(cls, sun: int) -> None: - if sun < 0: - raise ValueError("Sun level cannot be negative") - cls.__sun = sun - - @classmethod - def get_name(cls) -> str: - return cls.__name - - @classmethod - def get_water(cls) -> int: - return cls.__water - - @classmethod - def get_sun(cls) -> int: - return cls.__sun - - def __init__(self, name: str, water: int, sun: int) -> None: + def __init__(self, name: str, water_level: int, sunlight_hours: int) -> None: + if name == "": + raise Exception("Plant name cannot be empty") self.set_name(name) - self.set_water(water) - self.set_sun(sun) + self.__water_level = water_level + self.__sunlight_hours = sunlight_hours + print(f"Added {name} successfully") + + def get_name(self) -> str: + return self.__name + + def get_water_level(self) -> int: + return self.__water_level + + def get_sunlight_hours(self) -> int: + return self.__sunlight_hours + + def set_name(self, name: str) -> None: + if name == "": + raise Exception("Name cannot be empty") + self.__name = name + + def set_water_level(self, water_level: int) -> None: + if water_level < 1: + raise WaterError(f"Water level {water_level} is too low (min 1)") + if water_level > 10: + raise WaterError(f"Water level {water_level} is too high (max 10)") + self.__water_level = water_level + + def set_sunlight_hours(self, sunlight_hours: int) -> None: + if sunlight_hours < 2: + raise SunlightError(f"Sunlight hours {sunlight_hours} is too low (min 2)") + if sunlight_hours > 12: + raise SunlightError(f"Sunlight hours {sunlight_hours} is too high (max 12)") + self.__sunlight_hours = sunlight_hours + + def water_plant(self) -> None: + self.__water_level += 1 + print(f"Watering {self.__name} - success") class GardenManager: - __plants: list[Plant] + garden: list[Plant] __water_tank_level: int - @classmethod - def get_water_tank_level(cls) -> int: - return cls.__water_tank_level + class WaterTankError(Exception): + def __init__(self, message: str) -> None: + super().__init__() + self.message: str = message - @classmethod - def set_water_tank_level(cls, level: int) -> None: - cls.__water_tank_level = level + @override + def __str__(self) -> str: + return f"Caught WaterTankError: {self.message}" - def add_plant(self, name: str, water: int, sun: int) -> None: + + def __init__(self) -> None: + self.garden = [] + self.__water_tank_level = 0 + + def get_water_tank_level(self) -> int: + return self.__water_tank_level + + def set_water_tank_level(self, water_level: int) -> None: try: - new_plant = Plant(name, water, sun) - i = 0 - for n in self.__plants: - i = i + 1 - new_lst: list[Plant | None] = [None] * (i + 1) - i = 0 - for n in self.__plants: - new_lst[i] = n - i = i + 1 - new_lst[i] = new_plant - print("Added", name, "successfully") - except ValueError as err: + if water_level < 0: + raise self.WaterTankError("Water level cannot be negative") + self.__water_tank_level = water_level + except self.WaterTankError as err: + print(err) + + def add_plants_to_garden(self, plants: list[tuple[str, int, int]]) -> None: + try: + for a, b, c in plants: + self.garden.append(Plant(a, b, c)) + except Exception as err: + print("Error adding plant:", err) + + def check_plants_health(self) -> None: + try: + for plant in self.garden: + if plant.get_water_level() < 1: + raise WaterError(f"{plant.get_name()}: Water level {plant.get_water_level()} is too low (min 1)") + elif plant.get_water_level() > 10: + raise WaterError(f"{plant.get_name()}: Water level {plant.get_water_level()} is too high (max 10)") + elif plant.get_sunlight_hours() < 2: + raise SunlightError(f"{plant.get_name()}: Sunlight hours {plant.get_sunlight_hours()} is too low (min 2)") + elif plant.get_sunlight_hours() > 12: + raise SunlightError(f"{plant.get_name()}: Sunlight hours {plant.get_sunlight_hours()} is too high (max 12)") + else: + print(f"{plant.get_name()}: healthy (water: {plant.get_water_level()}, sun: {plant.get_sunlight_hours()})") + except (WaterError, SunlightError) as err: print(err) def water_plants(self) -> None: - print("Watering plants...") + """Watering all plants""" try: print("Opening watering system") - for n in self.__plants: - if self.__water_tank_level <= 0: - raise Exception("Caught GardenError: Not enough water in tank") - n.set_water(n.get_water() + 1) - self.__water_tank_level = self.__water_tank_level - 1; - print("Watering", n.get_name(), "- success") - except Exception as err: - print(err); + for plant in self.garden: + if self.__water_tank_level > 0: + plant.water_plant() + self.__water_tank_level -= 1 + else: + raise self.WaterTankError("Water tank is empty") + except self.WaterTankError as err: + print(err) finally: print("Closing watering system (cleanup)") - def __init__(self) -> None: - self.__plants = [] - self.__water_tank_level = 0 + +def test_garden_management() -> None: + manager = GardenManager() + print("=== Garden Management System ===\n") + print("Adding plants to garden...") + manager.add_plants_to_garden([ + ("Rose", 5, 5), + ("Oak", 7, 2), + ("Chrysantem", 2, 6), + ("Tomato", 10, 3), + ("", 8, 7) + ]) + print("\nWatering plants...") + manager.set_water_tank_level(10) + manager.water_plants() + print("\nChecking plant health...") + manager.check_plants_health() + print("\nTesting error recovery...") + manager.set_water_tank_level(0) + manager.water_plants() + print("System recovered and continuing") + print("\nGarden management system test complet!") if __name__ == "__main__": - manager = GardenManager() - manager.set_water_tank_level(10) - manager.add_plant("Tomato", 2, 10) - manager.add_plant("Lettuce", 5, 7) - manager.water_plants() + test_garden_management()