Source code for human_requests.tools.base

import inspect
from functools import wraps
from typing import Any, Awaitable, Callable, Type, TypeVar

from playwright.async_api import Error as PlaywrightError

[docs] F = TypeVar("F", bound=Callable[..., Awaitable[Any]])
[docs] T = TypeVar("T", bound=Type)
[docs] def make_screenshot(method: F) -> F: @wraps(method) async def wrapper(self: Any, *args: Any, **kwargs: Any) -> Any: try: return await method(self, *args, **kwargs) except PlaywrightError: try: from ..human_page import HumanPage if not isinstance(self, HumanPage) or self.on_error_screenshot_path: await self.screenshot(path=self.on_error_screenshot_path or "error.png") except Exception as screenshot_error: print(f"Screenshot failed: {screenshot_error}") raise return wrapper # type: ignore[return-value]
[docs] def auto_wrap_methods(decorator: Callable) -> Callable[[T], T]: """ Фабрика декораторов класса. Применяет декоратор только к асинхронным методам класса, кроме магических методов. Синхронные методы не оборачиваются. """ def class_decorator(cls: T) -> T: for attr_name in dir(cls): # Пропускаем магические методы if attr_name.startswith("__") and attr_name.endswith("__"): continue attr = getattr(cls, attr_name) if not callable(attr): continue # Оборачиваем ТОЛЬКО асинхронные методы if not inspect.iscoroutinefunction(attr): continue # Если метод уже обёрнут (имеет __wrapped__), пропускаем if hasattr(attr, "__wrapped__"): continue wrapped = decorator(attr) setattr(cls, attr_name, wrapped) return cls return class_decorator