Sphinx 文档模块属性
Posted
技术标签:
【中文标题】Sphinx 文档模块属性【英文标题】:Sphinx document module properties 【发布时间】:2013-03-31 13:46:54 【问题描述】:我有一个模块应该有一个@property
,我通过将一个类设置为模块解决了这个问题。我从这个答案中得到了这个想法:Lazy module variables--can it be done?
我希望这是可重复且易于使用的,因此我为它制作了一个元类。这就像一个魅力。
问题是当使用 Sphinx 生成文档属性时没有记录。其他所有内容都按预期记录。我不知道如何解决这个问题,也许这是 Sphinx 的问题?
模块:
import sys
import types
class ClassAsModule(type):
def __new__(cls, name, bases, attrs):
# Make sure the name of the class is the module name.
name = attrs.pop('__module__')
# Create a class.
cls = type.__new__(cls, name, bases, attrs)
# Instantiate the class and register it.
sys.modules[name] = cls = cls(name)
# Update the dict so dir works properly
cls.__dict__.update(attrs)
class TestClass(types.ModuleType):
"""TestClass docstring."""
__metaclass__ = ClassAsModule
@property
def some_property(self):
"""Property docstring."""
pass
def meth():
"""meth doc"""
pass
以及用于生成/查看 Sphinx 文档的复制粘贴:
sphinx-apidoc . -o doc --full
sphinx-build doc html
xdg-open html/module.html
最重要的部分是记录类的属性。奖励积分还可以记录原始模块成员。
编辑:该类应记录为它所在的模块。该类以这种方式使用,因此应该以这种方式出现在 Sphinx 中。
所需输出示例:
Module Foo
TestClass docstring.
some_property
Property docstring.
meth()
meth doc
编辑 2: 我发现了一些可能有助于找到解决方案的东西。当具有以下内容的常规模块foo
时:
#: Property of foo
prop = 'test'
Sphinx 记录如下:
foo.prop = 'test'
Property of foo
如果prop
是类的属性,则同样有效。我还没弄清楚为什么它在我的特殊情况下不起作用。
【问题讨论】:
您的代码不起作用。ModMeta
未定义。你能发布工作代码吗?
@jterrace 复制粘贴失败。现在已修复;-)
删除了我的答案,因为您的原始代码有 __metaclass_
而不是 __metaclass__
,导致它不起作用。
你确定这真的像你想象的那样工作吗?方法/属性似乎无法访问模块命名空间。例如,如果我将meth()
中的pass
语句替换为return sys.path
,我会得到:AttributeError: 'NoneType' object has no attribute 'path'
如果我只返回“Hello”或类似的东西,但不能访问应该是全局变量,则效果很好。跨度>
你看到和我一样的行为吗?
【参考方案1】:
这是我的理解。
理论是:让一个突变体你的类像一个模块这种(有点hacky)的方式让sphinx认为他不需要(解析)模块的属性(因为它是一个类级范式)。所以,对于 sphinx,TestClass
是一个模块。
首先,要确保罪魁祸首是使类像模块一样工作的代码 - 让我们删除它:
class ClassAsModule(type):
pass
我们将在文档中看到:
package Package
script Module
class package.script.ClassAsModule
Bases: type
class package.script.TestClass
Bases: module
TestClass docstring.
meth()
meth doc
some_property
Property docstring.
如您所见,sphinx 读取属性没有任何问题。这里没什么特别的。
您的问题的可能解决方案是避免使用 @property
装饰器,并将其替换为调用 property
类构造函数。例如:
import sys
import types
class ClassAsModule(type):
def __new__(cls, name, bases, attrs):
# Make sure the name of the class is the module name.
name = attrs.pop('__module__')
# Create a class.
cls = type.__new__(cls, name, bases, attrs)
# Instantiate the class and register it.
sys.modules[name] = cls = cls(name)
# Update the dict so dir works properly
cls.__dict__.update(attrs)
class TestClass(types.ModuleType):
"""TestClass docstring."""
__metaclass__ = ClassAsModule
def get_some_property(self):
"""Property docstring."""
pass
some_property = property(get_some_property)
def meth(self):
"""meth doc"""
pass
对于 sphinx 生成的这段代码:
package Package
script Module
TestClass docstring.
package.script.get_some_property(self)
Property docstring.
package.script.meth(self)
meth doc
答案可能是一派胡言,但我希望它能为您指明正确的方向。
【讨论】:
遗憾的是,这错过了同步使用属性和文档的意义。 是的,但是,重要的是要了解@property
装饰器只是语法糖。正如我所建议的那样,通过实例化property
类来定义属性实际上与使用装饰器的方式相同。但是,可以肯定的是,在这种情况下,文档显示的情况有些不同。
我奖励你赏金,否则没有人会收到这些积分。我不会得到退款,也不会很快得到接受的答案,所以这似乎是“最好的”事情。
谢谢!你认为如果我在这个问题上开始赏金会公平吗?还是我们应该稍等一下?
我可以选择任何一种。 ;-) 最后的赏金没有达到预期的结果,所以我打算等待。【参考方案2】:
我发现最好的方法是保持文件内容与编写常规模块一样,然后最后替换 sys.modules
中的胚胎模块:
"""Module docstring. """
import sys
import types
def _some_property(self):
pass
some_property = property(_some_property)
"""Property docstring."""
def meth():
"""meth doc"""
pass
def _make_class_module(name):
mod = sys.modules[name]
cls = type('ClassModule', (types.ModuleType,), mod.__dict__)
clsmod = cls(name)
clsmod.__dict__.update(mod.__dict__)
clsmod.__wrapped__ = mod
sys.modules[name] = clsmod
_make_class_module(__name__)
文本文档:
mymod Module
************
Module docstring.
mymod.meth()
meth doc
mymod.some_property = None
Property docstring.
对于我使用的 Sphinx 版本(v1.1.3),看起来您必须显式应用属性构造函数(您不能将其用作装饰器),并且文档字符串必须放入文件中在顶层,在创建属性的构造函数调用之后的行上(它不能作为属性 getter 中的文档字符串工作)。不过,源代码仍然相当可读。
【讨论】:
以上是关于Sphinx 文档模块属性的主要内容,如果未能解决你的问题,请参考以下文章
Sphinx + GitHub + ReadtheDocs 创建电子书