1from types import TracebackType
2from typing import Optional, Type
3
4from .console import Console, RenderableType
5from .jupyter import JupyterMixin
6from .live import Live
7from .spinner import Spinner
8from .style import StyleType
9
10
11class Status(JupyterMixin):
12    """Displays a status indicator with a 'spinner' animation.
13
14    Args:
15        status (RenderableType): A status renderable (str or Text typically).
16        console (Console, optional): Console instance to use, or None for global console. Defaults to None.
17        spinner (str, optional): Name of spinner animation (see python -m rich.spinner). Defaults to "dots".
18        spinner_style (StyleType, optional): Style of spinner. Defaults to "status.spinner".
19        speed (float, optional): Speed factor for spinner animation. Defaults to 1.0.
20        refresh_per_second (float, optional): Number of refreshes per second. Defaults to 12.5.
21    """
22
23    def __init__(
24        self,
25        status: RenderableType,
26        *,
27        console: Optional[Console] = None,
28        spinner: str = "dots",
29        spinner_style: StyleType = "status.spinner",
30        speed: float = 1.0,
31        refresh_per_second: float = 12.5,
32    ):
33        self.status = status
34        self.spinner_style = spinner_style
35        self.speed = speed
36        self._spinner = Spinner(spinner, text=status, style=spinner_style, speed=speed)
37        self._live = Live(
38            self.renderable,
39            console=console,
40            refresh_per_second=refresh_per_second,
41            transient=True,
42        )
43
44    @property
45    def renderable(self) -> Spinner:
46        return self._spinner
47
48    @property
49    def console(self) -> "Console":
50        """Get the Console used by the Status objects."""
51        return self._live.console
52
53    def update(
54        self,
55        status: Optional[RenderableType] = None,
56        *,
57        spinner: Optional[str] = None,
58        spinner_style: Optional[StyleType] = None,
59        speed: Optional[float] = None,
60    ) -> None:
61        """Update status.
62
63        Args:
64            status (Optional[RenderableType], optional): New status renderable or None for no change. Defaults to None.
65            spinner (Optional[str], optional): New spinner or None for no change. Defaults to None.
66            spinner_style (Optional[StyleType], optional): New spinner style or None for no change. Defaults to None.
67            speed (Optional[float], optional): Speed factor for spinner animation or None for no change. Defaults to None.
68        """
69        if status is not None:
70            self.status = status
71        if spinner_style is not None:
72            self.spinner_style = spinner_style
73        if speed is not None:
74            self.speed = speed
75        if spinner is not None:
76            self._spinner = Spinner(
77                spinner, text=self.status, style=self.spinner_style, speed=self.speed
78            )
79            self._live.update(self.renderable, refresh=True)
80        else:
81            self._spinner.update(
82                text=self.status, style=self.spinner_style, speed=self.speed
83            )
84
85    def start(self) -> None:
86        """Start the status animation."""
87        self._live.start()
88
89    def stop(self) -> None:
90        """Stop the spinner animation."""
91        self._live.stop()
92
93    def __rich__(self) -> RenderableType:
94        return self.renderable
95
96    def __enter__(self) -> "Status":
97        self.start()
98        return self
99
100    def __exit__(
101        self,
102        exc_type: Optional[Type[BaseException]],
103        exc_val: Optional[BaseException],
104        exc_tb: Optional[TracebackType],
105    ) -> None:
106        self.stop()
107
108
109if __name__ == "__main__":  # pragma: no cover
110
111    from time import sleep
112
113    from .console import Console
114
115    console = Console()
116    with console.status("[magenta]Covid detector booting up") as status:
117        sleep(3)
118        console.log("Importing advanced AI")
119        sleep(3)
120        console.log("Advanced Covid AI Ready")
121        sleep(3)
122        status.update(status="[bold blue] Scanning for Covid", spinner="earth")
123        sleep(3)
124        console.log("Found 10,000,000,000 copies of Covid32.exe")
125        sleep(3)
126        status.update(
127            status="[bold red]Moving Covid32.exe to Trash",
128            spinner="bouncingBall",
129            spinner_style="yellow",
130        )
131        sleep(5)
132    console.print("[bold green]Covid deleted successfully")
133