﻿"""
Zadanie 03: Propagacja i ponowne zgłaszanie (raise)

Zadanie uczy mechanizmu propagacji wyjątków. Przechwytujemy wyjątek na niższym poziomie
(np. w funkcji matematycznej) tylko po to, żeby go zalogować, a następnie "puszczamy"
go dalej (re-raise) za pomocą pustego 'raise', aby mógł zostać obsłużony wyżej,
zachowując pełen Traceback.
"""

def dziel(a: float, b: float) -> float:
    """
    Funkcja wykonująca dzielenie dwóch liczb, która aktywnie przechwytuje 
    ZeroDivisionError w celu zalogowania incydentu.
    
    Args:
        a (float): Dzielna.
        b (float): Dzielnik.
        
    Returns:
        float: Wynik dzielenia.
        
    Raises:
        ZeroDivisionError: Gdy b wynosi 0.
    """
    try:
        wynik = a / b
        return wynik
    except ZeroDivisionError:
        # Przechwyciliśmy błąd, więc program nie "wybuchnie" w tym miejscu,
        # ale naszą intencją tutaj jest jedynie ZALOGOWANIE problemu, a nie jego naprawa.
        # W architekturze wielowarstwowej często logujemy błąd w miejscu jego wystąpienia
        # (np. do pliku lub na konsolę dla administratora).
        print("LOG: Wykryto próbę dzielenia przez zero!")
        
        # Słowo kluczowe 'raise' użyte samo (bez podania obiektu wyjątku) w bloku except
        # powoduje PONOWNE zgłoszenie aktualnie przechwyconego wyjątku.
        # Różni się to od 'raise e' tym, że zachowuje pełen, oryginalny Traceback
        # (nie nadpisuje informacji o miejscu wyrzucenia błędu miejscem tego 'raise').
        raise


def policz(a: float, b: float) -> None:
    """
    Funkcja z wyższej warstwy aplikacji, która wywołuje funkcję dziel(),
    i zawiera własną obsługę błędów, by bezpiecznie komunikować się z użytkownikiem.
    """
    print(f">>> policz({a}, {b})")
    try:
        wynik = dziel(a, b)
        print(f"Wynik to: {wynik}")
    except ZeroDivisionError as e:
        # Tutaj, na wyższym poziomie, prezentujemy informację użytkownikowi końelowemu.
        # Dzięki temu kod diagnostyczny (logowanie) jest oddzielony od kodu UI.
        print(f"BŁĄD DLA UŻYTKOWNIKA: Nie możesz dzielić przez zero. ({e})")


if __name__ == "__main__":
    # Test 1: Poprawne dzielenie
    policz(10, 2)
    print()
    
    # Test 2: Dzielenie przez zero
    # To wywołanie najpierw wygeneruje LOG z funkcji dziel(), a następnie błąd
    # "wypadnie" z niej z powodu 'raise' i zostanie złapany przez except w policz().
    policz(10, 0)
    print()
    
    # Demonstrujemy działanie zachowania Tracebacku
    print(">>> Demonstracja Tracebacku (aby pokazać z której linijki wywodzi się błąd):")
    try:
        dziel(5, 0)
    except Exception as e:
        import traceback
        traceback.print_exc()
