python 装饰器采用 1 个位置参数,但在为 pytest 修改后给出了 5 个

python decorator takes 1 positional argument but 5 were given after modifying for pytest

我希望能为以下代码提供一些帮助,因为我对 Python 还比较陌生,尽管花了无数天时间试图弄清楚哪里出了问题,但我似乎无法发现我犯的错误。

我从媒体上的一篇文章中改编了以下代码来创建日志装饰器,然后对其进行增强以尝试从日志中“编辑 pandas df 和字典”。使用 functools 导致 pytest 和 pytest fixtures 出现问题。关于堆栈溢出的 post 建议放弃 functools 以支持装饰器。

def log_decorator(_func=None):
    def log_decorator_info(func):
        def log_decorator_wrapper(*args, **kwargs):
        
            _logger = Logger()
            logger_obj = _logger.get_logger()

            args_passed_in_function = args_excl_df_dict(*args)
            kwargs_passed_in_function = kwargs_excl_df_dict(**kwargs)
           formatted_arguments = join_args_kwargs(args_passed_in_function,kwargs_passed_in_function)
        
            py_file_caller = getframeinfo(stack()[1][0])
            extra_args = { 'func_name_override': func.__name__,'file_name_override': os.path.basename(py_file_caller.filename) }

            """ Before to the function execution, log function details."""
            logger_obj.info(f"Begin function - Arguments: {formatted_arguments}", extra=extra_args)
        
            try:
                """ log return value from the function """
            
                args_returned_from_function = args_excl_df_dict(func(*args))
                kwargs_returned_from_function = []
                formatted_arguments = join_args_kwargs(args_returned_from_function,kwargs_returned_from_function)
            
                logger_obj.info(f"End function - Returned: {formatted_arguments}", extra=extra_args)
       
            except:
                """log exception if occurs in function"""
                error_raised = str(sys.exc_info()[1])
            
                logger_obj.error(f"Exception: {str(sys.exc_info()[1])}",extra=extra_args)
            
                msg_to_send = f"{func.__name__} {error_raised}"
               send_alert(APP_NAME,msg_to_send,'error')
            
               raise
            return func(*args, **kwargs)
        return decorator.decorator(log_decorator_wrapper, func)
    if _func is None:
        return log_decorator_info
    else:
        return log_decorator_info(_func)

修改了上面的代码后,我无法弄清楚是什么导致了以下错误

args_returned_from_function = args_excl_df_dict(func(*args)) TypeError: test_me() takes 4 positional arguments but 5 were given

日志装饰器依赖的其他功能

def args_excl_df_dict(*args):
    args_list = []
    for a in args:
        if isinstance(a,(pd.DataFrame,dict)):
            a = 'redacted from log'
            args_list.append(repr(a))
        else: 
            args_list.append(repr(a))
    return args_list

def kwargs_excl_df_dict(**kwargs):
    kwargs_list = []
    for k, v in kwargs.items():
        if isinstance(v,(dict,pd.DataFrame)):
            v = 'redacted from log'
            kwargs_list.append(f"{k}={v!r}")
        else:
            kwargs_list.append(f"{k}={v!r}")
    return kwargs_list

def join_args_kwargs(args,kwargs):

    formatted_arguments = ", ".join(args + kwargs)
    return str(formatted_arguments)

这是调用装饰器的代码

@log_decorator.log_decorator()
def test_me(a, b, c, d):
    return a, b

test_me(string, number, dictionary, pandas_df)

如果您的代码与编辑器中的一样,也许可以查看前三个函数的缩进。然后从那里开始往下移动

我认为问题在于包装器将函数作为参数包含在函数中。

尝试添加此行,看看是否有帮助

args = args[1:]

将您的 log_decorator_wrapper 功能置于顶部。像这样。

def log_decorator(_func=None):
    def log_decorator_info(func):
        def log_decorator_wrapper(*args, **kwargs):

            args = args[1:]   # < -------------------here
            _logger = Logger()
            logger_obj = _logger.get_logger()

            args_passed_in_function = args_excl_df_dict(*args)
            kwargs_passed_in_function = kwargs_excl_df_dict(**kwargs)
           formatted_arguments = join_args_kwargs(args_passed_in_function,kwargs_passed_in_function)
        
            py_file_caller = getframeinfo(stack()[1][0])
            extra_args = { 'func_name_override': func.__name__,'file_name_override': os.path.basename(py_file_caller.filename) }

            """ Before to the function execution, log function details."""
            logger_obj.info(f"Begin function - Arguments: {formatted_arguments}", extra=extra_args)
        
            try:
                """ log return value from the function """
            
                args_returned_from_function = args_excl_df_dict(func(*args))
                kwargs_returned_from_function = []
                formatted_arguments = join_args_kwargs(args_returned_from_function,kwargs_returned_from_function)
            
                logger_obj.info(f"End function - Returned: {formatted_arguments}", extra=extra_args)
       
            except:
                """log exception if occurs in function"""
                error_raised = str(sys.exc_info()[1])
            
                logger_obj.error(f"Exception: {str(sys.exc_info()[1])}",extra=extra_args)
            
                msg_to_send = f"{func.__name__} {error_raised}"
               send_alert(APP_NAME,msg_to_send,'error')
            
               raise
            return func(*args, **kwargs)

        return decorator.decorator(log_decorator_wrapper, func)
    if _func is None:
        return log_decorator_info
    else:
        return log_decorator_info(_func)