如何获得包装的function .__code__.Co_filename with decorator?



如下所示的简单文件夹结构,test.py中的所有函数都有关键字decorator。

lib
|--- keyword.py
main
|--- test.py

Keyword.py

from functools import wraps
def keyword(name=None, tags=(), types=()):
def _method_wrapper(func):
@wraps(func)
def _passargs(self, *args, **kwargs):  
print(func.__code__.co_filename)  # --> '..maintest.py'
return func(self, *args, **kwargs)
print(_passargs.__code__.co_filename)  # --> '..libkeyword.py'

return _passargs
return _method_wrapper 

注:print(..)只是一个例子,我需要两个_passargs&func有相同的代码对象,而不是打印另一个变量:)

可以看到,_passargs得到了错误的co_filename

这是来自robotframeworkkeyword.py,我根据自己的目的修改了它。然而,我没能弄清楚如何使_passargs&func有正确的源文件位置,因此robot.libdoc可以生成doc。libspec正确。

有人能帮忙吗?

期望

func.__code__.co_filename = '..maintest.py'
_passargs.__code__.co_filename = '..maintest.py'

Python版本= 3.8.10

在这里回答我自己的问题,以帮助那些可能有同样问题的人。

原来的decorator function:

from functools import wraps
def keyword(name=None, tags=(), types=()):
def _method_wrapper(func):
@wraps(func)
def _passargs(self, *args, **kwargs):  
print(func.__code__.co_filename)  # --> '..maintest.py'
return func(self, *args, **kwargs)
print(_passargs.__code__.co_filename)  # --> '..libkeyword.py'

return _passargs
return _method_wrapper 

大多数情况下,我们只需要最后一层装饰器(在这个例子中是return func(self, *args, **kwargs))来返回包装函数的适当属性。

然而,在我的例子中,有一个函数将在初始化类期间扫描带有keyword装饰器的所有函数。它不会进入def _passargs级别,因为我们没有提供任何参数,而只是试图获得包装的func (return _passargs)相关属性。

要解决这个问题,我们只能在运行时覆盖co_filename

这是在decorator中重写__code__对象的解决方案。

from types import CodeType
from functools import wraps

def keyword(name=None, tags=(), types=()):
def _method_wrapper(func):
@wraps(func)
def _passargs(self, *args, **kwargs):  
print(func.__code__.co_filename)  # --> '..maintest.py'
return func(self, *args, **kwargs)
fix_co_filename(_passargs, func.__code__.co_filename)
print(_passargs.__code__.co_filename)  # --> '..maintest.py'

return _passargs
return _method_wrapper 

def fix_co_filename(func, co_filename):
fn_code = func.__code__
func.__code__ = CodeType(
fn_code.co_argcount,
fn_code.co_posonlyargcount,
fn_code.co_kwonlyargcount,
fn_code.co_nlocals,
fn_code.co_stacksize,
fn_code.co_flags,
fn_code.co_code,
fn_code.co_consts,
fn_code.co_names,
fn_code.co_varnames,
co_filename,
fn_code.co_name,
fn_code.co_firstlineno,
fn_code.co_lnotab,
fn_code.co_freevars,
fn_code.co_cellvars)

最新更新