Add @noncritical and @repeat decorators

This commit is contained in:
Joscha 2021-05-05 23:36:54 +02:00
parent bbfdadc463
commit 5497dd2827

View File

@ -3,7 +3,8 @@ from abc import ABC, abstractmethod
from contextlib import asynccontextmanager from contextlib import asynccontextmanager
from pathlib import PurePath from pathlib import PurePath
# TODO In Python 3.9 and above, AsyncContextManager is deprecated # TODO In Python 3.9 and above, AsyncContextManager is deprecated
from typing import AsyncContextManager, AsyncIterator, Optional from typing import (Any, AsyncContextManager, AsyncIterator, Awaitable,
Callable, Optional, Protocol, TypeVar)
from rich.markup import escape from rich.markup import escape
@ -18,6 +19,78 @@ class CrawlerLoadException(Exception):
pass pass
class CrawlerMemberFunction(Protocol):
def __call__(
self,
__self: "Crawler",
*__args: Any,
**__kwargs: Any,
) -> None:
pass
Wrapped = TypeVar("Wrapped", bound=CrawlerMemberFunction)
def noncritical(f: Wrapped) -> Wrapped:
def wrapper(self: "Crawler", *args: Any, **kwargs: Any) -> None:
try:
f(self, *args, **kwargs)
except Exception as e:
self.print(f"[red]Something went wrong: {escape(str(e))}")
self._error_free = False
return wrapper # type: ignore
def repeat(attempts: int) -> Callable[[Wrapped], Wrapped]:
def decorator(f: Wrapped) -> Wrapped:
def wrapper(self: "Crawler", *args: Any, **kwargs: Any) -> None:
for _ in range(attempts - 1):
try:
f(self, *args, **kwargs)
return
except Exception:
pass
f(self, *args, **kwargs)
return wrapper # type: ignore
return decorator
class ACrawlerMemberFunction(Protocol):
def __call__(
self,
__self: "Crawler",
*__args: Any,
**__kwargs: Any,
) -> Awaitable[None]:
pass
AWrapped = TypeVar("AWrapped", bound=ACrawlerMemberFunction)
def anoncritical(f: AWrapped) -> AWrapped:
async def wrapper(self: "Crawler", *args: Any, **kwargs: Any) -> None:
try:
await f(self, *args, **kwargs)
except Exception as e:
self.print(f"[red]Something went wrong: {escape(str(e))}")
self._error_free = False
return wrapper # type: ignore
def arepeat(attempts: int) -> Callable[[AWrapped], AWrapped]:
def decorator(f: AWrapped) -> AWrapped:
async def wrapper(self: "Crawler", *args: Any, **kwargs: Any) -> None:
for _ in range(attempts - 1):
try:
await f(self, *args, **kwargs)
return
except Exception:
pass
await f(self, *args, **kwargs)
return wrapper # type: ignore
return decorator
class Crawler(ABC): class Crawler(ABC):
def __init__( def __init__(
self, self,
@ -51,6 +124,8 @@ class Crawler(ABC):
self._output_dir = OutputDirectory( self._output_dir = OutputDirectory(
output_dir, redownload, on_conflict, self._conductor) output_dir, redownload, on_conflict, self._conductor)
self._error_free = False
def print(self, text: str) -> None: def print(self, text: str) -> None:
""" """
Print rich markup to the terminal. Crawlers *must* use this function to Print rich markup to the terminal. Crawlers *must* use this function to