pferd/PFERD/conductor.py

92 lines
2.5 KiB
Python
Raw Normal View History

2021-04-29 11:25:00 +02:00
import asyncio
from contextlib import asynccontextmanager, contextmanager
2021-04-29 14:23:28 +02:00
from types import TracebackType
from typing import AsyncIterator, Iterator, List, Optional, Type
2021-04-29 11:25:00 +02:00
from rich.progress import Progress, TaskID
class ProgressBar:
def __init__(self, progress: Progress, taskid: TaskID):
self._progress = progress
self._taskid = taskid
def advance(self, amount: float = 1) -> None:
self._progress.advance(self._taskid, advance=amount)
def set_total(self, total: float) -> None:
2021-05-06 01:02:40 +02:00
self._progress.update(self._taskid, total=total)
2021-04-29 11:25:00 +02:00
class TerminalConductor:
def __init__(self) -> None:
self._stopped = False
self._lock = asyncio.Lock()
self._progress = Progress()
self._lines: List[str] = []
2021-04-29 14:23:28 +02:00
async def _start(self) -> None:
2021-04-29 15:26:10 +02:00
for task in self._progress.tasks:
task.visible = True
self._progress.start()
self._stopped = False
2021-04-29 11:25:00 +02:00
2021-04-29 15:26:10 +02:00
for line in self._lines:
self.print(line)
self._lines = []
2021-04-29 11:25:00 +02:00
2021-04-29 14:23:28 +02:00
async def _stop(self) -> None:
2021-04-29 15:26:10 +02:00
self._stopped = True
for task in self._progress.tasks:
task.visible = False
self._progress.stop()
2021-04-29 11:25:00 +02:00
2021-04-29 14:23:28 +02:00
async def __aenter__(self) -> None:
2021-04-29 15:26:10 +02:00
async with self._lock:
await self._start()
2021-04-29 14:23:28 +02:00
async def __aexit__(
self,
exc_type: Optional[Type[BaseException]],
exc_value: Optional[BaseException],
traceback: Optional[TracebackType],
) -> Optional[bool]:
2021-04-29 15:26:10 +02:00
async with self._lock:
await self._stop()
2021-04-29 14:23:28 +02:00
return None
2021-04-29 11:25:00 +02:00
def print(self, line: str) -> None:
if self._stopped:
self._lines.append(line)
else:
2021-04-29 15:26:10 +02:00
self._progress.console.print(line)
2021-04-29 11:25:00 +02:00
@asynccontextmanager
async def exclusive_output(self) -> AsyncIterator[None]:
2021-04-29 11:25:00 +02:00
async with self._lock:
2021-04-29 15:26:10 +02:00
await self._stop()
2021-04-29 11:25:00 +02:00
try:
yield
finally:
2021-04-29 15:26:10 +02:00
await self._start()
2021-04-29 11:25:00 +02:00
@contextmanager
def progress_bar(
2021-04-29 11:25:00 +02:00
self,
description: str,
total: Optional[float] = None,
2021-04-29 11:25:00 +02:00
) -> Iterator[ProgressBar]:
if total is None:
# Indeterminate progress bar
taskid = self._progress.add_task(description, start=False)
else:
taskid = self._progress.add_task(description, total=total)
2021-04-29 11:25:00 +02:00
bar = ProgressBar(self._progress, taskid)
try:
yield bar
finally:
self._progress.remove_task(taskid)