mypy 的类型提示,用于 staticmethod/classmethod 上的装饰器

问题描述 投票:0回答:1

我正在为记录器库编写一个帮助程序,该库具有具有特定跟踪(调试)日志记录的装饰器。

代码本身是正确的(它部分基于现有库),但我很难找到如何使 mypy 接受它的类型。

问号是我在类型方面遇到问题的地方。或者也许问题更普遍

对于静态方法:

def trace_static_method(_staticmethod: staticmethod) -> staticmethod:
    @wraps(_staticmethod.__func__)  # this generate mypy error for incorrect type
    def wrapper(*args: ???, **kwargs: ???) -> ???:
        return _log_trace(_staticmethod.__func__, *args, **kwargs)
    return staticmethod(wrapper)  # this generate mypy error for incorrect type

对于类方法:

def trace_class_method(_classmethod: classmethod) -> classmethod:
    @wraps(_classmethod.__func__)  # this generate mypy error for incorrect type
    def wrapper(_cls: ???, *args: ???, **kwargs: ???) -> ???:
        method = _classmethod.__get__(None, _cls)  # this generate mypy error for incorrect type
        return _log_trace(method, *args, **kwargs)
    return classmethod(wrapper)  # this generate mypy error for incorrect type

日志跟踪:

def _log_trace(func: Callable[P, T], *args: P.args, **kwargs: P.kwargs) -> T:
    name = func.__qualname__
    module = func.__module__
    logger_ = logger.opt(depth=1)
    logger_.log("TRACE", "{}.{} CALL args={}, kwargs={}", module, name, args, kwargs)
    result = func(*args, **kwargs)
    logger_.log("TRACE", "{}.{} RETURN {}", module, name, result)
    return result

简单函数装饰器的工作类型:

def trace(func: Callable[P, T]) -> Callable[P, T]:
    @wraps(func)
    def wrapper(*args: P.args, **kwargs: P.kwargs) -> T:
        return _log_trace(func, *args, **kwargs)
    return wrapper

编辑:为静态方法添加正确的类型实际上非常简单:

def trace_static_method(_staticmethod: staticmethod[P, T]) -> staticmethod[P, T]:

    @wraps(_staticmethod.__func__)
    def wrapper(*args: P.args, **kwargs: P.kwargs) -> T:
        return _log_trace(_staticmethod.__func__, *args, **kwargs)

    return staticmethod(wrapper)
python python-typing mypy
1个回答
0
投票

正确的打字。适用于 mypy 1.6.1.

P = ParamSpec("P")
T = TypeVar("T")
R_co = TypeVar("R_co", covariant=True)

def _log_trace(func: Callable[P, T], *args: P.args, **kwargs: P.kwargs) -> T:
    """Log a function call and return."""
    trace_logger = logger.opt(depth=1).bind(
        trace_name=func.__qualname__,
        trace_module=func.__module__,
    )
    trace_logger.trace("CALL args={}, kwargs={}", args, kwargs)
    result = func(*args, **kwargs)
    trace_logger.trace("RETURN {}", result)
    return result

def trace(func: Callable[P, T]) -> Callable[P, T]:
    """Trace a function."""

    @wraps(func)
    def wrapper(*args: P.args, **kwargs: P.kwargs) -> T:
        return _log_trace(func, *args, **kwargs)

    return wrapper


def trace_instance_method(func: Callable[P, T]) -> Callable[P, T]:
    """Trace a method."""

    @wraps(func)
    def wrapper(*args: P.args, **kwargs: P.kwargs) -> T:
        _self: object = args[0]
        method = func.__get__(_self, _self.__class__)
        return _log_trace(method, *args[1:], **kwargs)

    return wrapper


def trace_static_method(
    _staticmethod: "staticmethod[P, R_co]",
) -> "staticmethod[P, R_co]":
    """Trace a method wrapped in @staticmethod."""

    @wraps(_staticmethod.__func__)
    def wrapper(*args: P.args, **kwargs: P.kwargs) -> R_co:
        return _log_trace(_staticmethod.__func__, *args, **kwargs)

    return staticmethod(wrapper)


def trace_class_method(
    _classmethod: "classmethod[T, P, R_co]",
) -> "classmethod[T, P, R_co]":
    """Trace a method wrapped in @classmethod"""

    @wraps(_classmethod.__func__)
    def wrapper(_cls: type[T], *args: P.args, **kwargs: P.kwargs) -> R_co:
        method = _classmethod.__get__(None, _cls)
        return _log_trace(method, *args, **kwargs)

    return classmethod(wrapper)
© www.soinside.com 2019 - 2024. All rights reserved.