如下所示的简单文件夹结构,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
。
这是来自robotframework
keyword.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)