[英]Preserve default arguments of wrapped/decorated Python function in Sphinx documentation
How can I replace *args
and **kwargs
with the real signature in the documentation of decorated functions?如何用装饰函数文档中的真实签名替换
*args
和**kwargs
?
Let's say I have the following decorator and decorated function:假设我有以下装饰器和装饰功能:
import functools
def mywrapper(func):
@functools.wraps(func)
def new_func(*args, **kwargs):
print('Wrapping Ho!')
return func(*args, **kwargs)
return new_func
@mywrapper
def myfunc(foo=42, bar=43):
"""Obscure Addition
:param foo: bar!
:param bar: bla bla
:return: foo + bar
"""
return foo + bar
Accordingly, calling print(myfunc(3, 4))
gives us:因此,调用
print(myfunc(3, 4))
给我们:
Wrapping Ho!
7
So far so good.到现在为止还挺好。 I also want my library containing
myfunc
properly documented with Sphinx.我还希望我的库包含使用 Sphinx 正确记录的
myfunc
。 However, if I include my function in my sphinx html page via:但是,如果我通过以下方式将我的函数包含在我的 sphinx html 页面中:
.. automodule:: mymodule
:members: myfunc
It will actually show up as:它实际上会显示为:
Obscure Addition模糊加成
How can I get rid of the generic myfunc(*args, **kwargs)
in the title?如何摆脱标题中的通用
myfunc(*args, **kwargs)
? This should be replaced by myfunc(foo=42, bar=43) .这应该替换为myfunc(foo=42, bar=43) 。 How can I change sphinx or my decorator
mywrapper
such that the default keyword arguments are preserved in the documentation?如何更改 sphinx 或我的装饰器
mywrapper
以便在文档中保留默认关键字参数?
EDIT :编辑:
As pointed out this question has been asked before, but the answers are not so helpful.正如所指出的,这个问题以前曾被问过,但答案并不是那么有帮助。
However, I had an idea and wonder if this is possible.但是,我有一个想法,想知道这是否可能。 Does Sphinx set some environment variable that tells my module that it is actually imported by Sphinx?
Sphinx 是否设置了一些环境变量来告诉我的模块它实际上是由 Sphinx 导入的? If so, I could simply monkey-patch my own wrappers.
如果是这样,我可以简单地修补我自己的包装。 If my module is imported by Sphinx my wrappers return the original functions instead of wrapping them.
如果我的模块是由 Sphinx 导入的,我的包装器将返回原始函数而不是包装它们。 Thus, the signature is preserved.
因此,签名被保留。
I came up with a monkey-patch for functools.wraps
.我为
functools.wraps
想出了一个猴子补丁。 Accordingly, I simply added this to the conf.py
script in my project documentation's sphinx source
folder:因此,我只是将其添加到我的项目文档的 sphinx
source
文件夹中的conf.py
脚本中:
# Monkey-patch functools.wraps
import functools
def no_op_wraps(func):
"""Replaces functools.wraps in order to undo wrapping.
Can be used to preserve the decorated function's signature
in the documentation generated by Sphinx.
"""
def wrapper(decorator):
return func
return wrapper
functools.wraps = no_op_wraps
Hence, when building the html page via make html
, functools.wraps
is replaced with this decorator no_op_wraps
that does absolutely nothing but simply return the original function.因此,当通过
make html
构建 html 页面时, functools.wraps
被替换为这个装饰器no_op_wraps
,它除了简单地返回原始函数之外什么都不做。
You ordinarily can't.你通常不能。 That is because the variable names used as parameters in the wrapped function are not even present on the wrapped function - so Sphinx do not know about them.
那是因为在包装函数中用作参数的变量名称甚至不存在于包装函数中 - 所以 Sphinx 不知道它们。
That is a known complicated issue in Python - so much that recent versions - including not only Python 3, but also Python 2.7 included a __wrapped__
attribute on class decorated that make the proper use from functools.wraps
- that way, upon inspecting the decorated function one is able to know about the actual wrrapped function by looking at __wrapped__
.这是 Python 中一个已知的复杂问题 - 以至于最近的版本 - 不仅包括 Python 3,还包括 Python 2.7 在装饰类上包含一个
__wrapped__
属性,可以从functools.wraps
正确使用 - 这样,在检查装饰函数时可以通过查看__wrapped__
来了解实际的包装函数。 Unfortunatelly, Sphinxs ignores the __wrapped__
, and show the info on the wrapper function instead.不幸的是,Sphinxs 忽略了
__wrapped__
,而是显示包装函数的信息。
SO, one thing to do is certainly to report this as a bug to the Sphinx project itself - it should take __wrapped__
in account.所以,要做的一件事当然是将此作为错误报告给 Sphinx 项目本身 - 它应该考虑
__wrapped__
。
A meantime workaround for that would be to change the wrapper function to actually include more information about the wrapped - like its signature - so you could write another function to be called in place of "functools.wraps" for your project, which does just that: pre-pend the function signature to its docstring, if any.在此期间的解决方法是更改包装器函数以实际包含有关包装的更多信息(例如其签名),因此您可以编写另一个要调用的函数来代替项目的“functools.wraps”,它就是这样做的: 将函数签名预先添加到其文档字符串中,如果有的话。 Unfortunatelly, retrieving the function signatures in Python older than 3.3 is tricky - (for 3.3 and newer, check https://docs.python.org/3/library/inspect.html#inspect-signature-object ) - but anyway, for a naive form, you could write another version of "wraps" along:
不幸的是,在 Python 3.3 之前检索函数签名很棘手 - (对于 3.3 和更高版本,请检查https://docs.python.org/3/library/inspect.html#inspect-signature-object ) - 但无论如何,对于一个天真的形式,你可以写另一个版本的“包装”:
def wraps(original_func):
wrap_decorator = functools.wraps(original_func)
def re_wrapper(func):
wrapper = wrap_decorator(func)
poorman_sig = original_func.__code__.co_varnames[
:original_func.__code__.co_argcount]
wrapper.__doc__ = "{} ({})\n\n{}".format (
original_func.__name__, ", ".join(poorman_sig),
wrapper.__doc__)
return wrapper
return re_wrapper
And use that instead of "functools.wraps".并使用它而不是“functools.wraps”。 It would at least add a line with the parameter names, (but not th e defalt values) as first line in the docs.
它至少会添加一行带有参数名称的行(但不是默认值)作为文档中的第一行。
---Hmm..maybe it would be easier just to patch Sphinx to use __wrapped__
before getting this done right. ---嗯..
__wrapped__
在正确完成此操作之前修补 Sphinx 以使用__wrapped__
会更容易。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.