mirror of
				https://github.com/Garmelon/PFERD.git
				synced 2025-10-31 21:02:42 +01:00 
			
		
		
		
	Test and fix exclusive output
This commit is contained in:
		| @@ -3,7 +3,6 @@ from contextlib import asynccontextmanager, contextmanager | ||||
| from types import TracebackType | ||||
| from typing import AsyncIterator, Iterator, List, Optional, Type | ||||
|  | ||||
| import rich | ||||
| from rich.progress import Progress, TaskID | ||||
|  | ||||
|  | ||||
| @@ -24,19 +23,25 @@ class TerminalConductor: | ||||
|         self._lines: List[str] = [] | ||||
|  | ||||
|     async def _start(self) -> None: | ||||
|         async with self._lock: | ||||
|             for line in self._lines: | ||||
|                 rich.print(line) | ||||
|             self._lines = [] | ||||
|  | ||||
|         for task in self._progress.tasks: | ||||
|             task.visible = True | ||||
|         self._progress.start() | ||||
|  | ||||
|         self._stopped = False | ||||
|  | ||||
|         for line in self._lines: | ||||
|             self.print(line) | ||||
|         self._lines = [] | ||||
|  | ||||
|     async def _stop(self) -> None: | ||||
|         async with self._lock: | ||||
|             self._progress.stop() | ||||
|         self._stopped = True | ||||
|  | ||||
|         for task in self._progress.tasks: | ||||
|             task.visible = False | ||||
|         self._progress.stop() | ||||
|  | ||||
|     async def __aenter__(self) -> None: | ||||
|         async with self._lock: | ||||
|             await self._start() | ||||
|  | ||||
|     async def __aexit__( | ||||
| @@ -45,6 +50,7 @@ class TerminalConductor: | ||||
|             exc_value: Optional[BaseException], | ||||
|             traceback: Optional[TracebackType], | ||||
|     ) -> Optional[bool]: | ||||
|         async with self._lock: | ||||
|             await self._stop() | ||||
|         return None | ||||
|  | ||||
| @@ -52,16 +58,16 @@ class TerminalConductor: | ||||
|         if self._stopped: | ||||
|             self._lines.append(line) | ||||
|         else: | ||||
|             rich.print(line) | ||||
|             self._progress.console.print(line) | ||||
|  | ||||
|     @asynccontextmanager | ||||
|     async def exclusive_output(self) -> AsyncIterator[None]: | ||||
|         async with self._lock: | ||||
|             self._stop() | ||||
|             await self._stop() | ||||
|             try: | ||||
|                 yield | ||||
|             finally: | ||||
|                 self._start() | ||||
|                 await self._start() | ||||
|  | ||||
|     @contextmanager | ||||
|     def progress_bar( | ||||
|   | ||||
| @@ -38,6 +38,9 @@ class Crawler(ABC): | ||||
|     def print(self, text: str) -> None: | ||||
|         self._conductor.print(text) | ||||
|  | ||||
|     def exclusive_output(self): | ||||
|         return self._conductor.exclusive_output() | ||||
|  | ||||
|     @asynccontextmanager | ||||
|     async def progress_bar( | ||||
|             self, | ||||
|   | ||||
| @@ -6,6 +6,7 @@ from typing import Any | ||||
| from rich.markup import escape | ||||
|  | ||||
| from ..crawler import Crawler | ||||
| from ..utils import ainput | ||||
|  | ||||
| DUMMY_TREE = { | ||||
|     "Blätter": { | ||||
| @@ -17,7 +18,7 @@ DUMMY_TREE = { | ||||
|         "Lösungen": { | ||||
|             "Blatt_01_Lösung.pdf": (), | ||||
|             "Blatt_02_Lösung.pdf": (), | ||||
|             "Blatt_03_Lösung.pdf": (), | ||||
|             "Blatt_03_Lösung.pdf": True, | ||||
|             "Blatt_04_Lösung.pdf": (), | ||||
|             "Blatt_05_Lösung.pdf": (), | ||||
|         }, | ||||
| @@ -39,7 +40,10 @@ class DummyCrawler(Crawler): | ||||
|         await self._crawl_entry(Path(), DUMMY_TREE) | ||||
|  | ||||
|     async def _crawl_entry(self, path: Path, value: Any) -> None: | ||||
|         if value == (): | ||||
|         if value is True: | ||||
|             async with self.exclusive_output(): | ||||
|                 await ainput(f"File {path}, please press enter: ") | ||||
|         if value == () or value is True: | ||||
|             n = random.randint(5, 20) | ||||
|             async with self.download_bar(path, n) as bar: | ||||
|                 await asyncio.sleep(random.random() / 2) | ||||
|   | ||||
| @@ -1,7 +1,30 @@ | ||||
| from typing import Optional | ||||
| import functools | ||||
| import contextvars | ||||
| import asyncio | ||||
| import getpass | ||||
| from typing import Any, Callable, Optional, TypeVar | ||||
|  | ||||
| T = TypeVar("T") | ||||
|  | ||||
|  | ||||
| def prompt_yes_no(query: str, default: Optional[bool]) -> bool: | ||||
| # TODO When switching to 3.9, use asyncio.to_thread instead of this | ||||
| async def to_thread(func: Callable[..., T], *args: Any, **kwargs: Any) -> T: | ||||
|     # https://github.com/python/cpython/blob/8d47f92d46a92a5931b8f3dcb4a484df672fc4de/Lib/asyncio/threads.py | ||||
|     loop = asyncio.get_event_loop() | ||||
|     ctx = contextvars.copy_context() | ||||
|     func_call = functools.partial(ctx.run, func, *args, **kwargs) | ||||
|     return await loop.run_in_executor(None, func_call) | ||||
|  | ||||
|  | ||||
| async def ainput(prompt: Optional[str] = None) -> str: | ||||
|     return await to_thread(lambda: input(prompt)) | ||||
|  | ||||
|  | ||||
| async def agetpass(prompt: Optional[str] = None) -> str: | ||||
|     return await to_thread(lambda: getpass.getpass(prompt)) | ||||
|  | ||||
|  | ||||
| async def prompt_yes_no(query: str, default: Optional[bool]) -> bool: | ||||
|     """ | ||||
|     Asks the user a yes/no question and returns their choice. | ||||
|     """ | ||||
| @@ -14,7 +37,7 @@ def prompt_yes_no(query: str, default: Optional[bool]) -> bool: | ||||
|         query += " [y/n] " | ||||
|  | ||||
|     while True: | ||||
|         response = input(query).strip().lower() | ||||
|         response = (await ainput(query)).strip().lower() | ||||
|         if response == "y": | ||||
|             return True | ||||
|         elif response == "n": | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Joscha
					Joscha